3

Is there any good reason not to run a brief unknown (30 line) assembly script inline in a usermode c program for dynamic analysis directly on my laptop?

There's only one system call to time, and at this point I can tell that it's a function that takes a c string and it's length, and performs some sort of encryption on it in a loop, which only iterates through the string as long as the length argument tells it.

I know that the script is (supposed to be) from a piece of malicious code, but for the life of me I can't think of any way it could possibly pwn my computer barring some sort of hardware bug (which seems unlikely given that the loop is ~ 7 instructions long and the strangest instruction in the whole script is a shr).

I know it sounds bad running an unknown piece of assembly code directly on the metal, but given my analysis up to this point I can't think of any way it could bite me or escape.

1 Answers1

4

Is there a reason you can't just study the code? 30 lines of ASM should be easy to understand. Just add comments explaining what each line does, and you'll understand it in no time. This will be even easier given how quickly you can look up exactly what an individual instruction does.

Although I would agree that it is unlikely to be capable of doing anything dangerous on its own with only a single syscall, you should never underestimate the ingenuity some developers can have. It is perfectly possible to design shellcode to trick a disassembler into showing you code which is not actually there, as DEF CON talk a few years ago pointed out. 30 lines of x86 assembly is plenty for a stage 1 payload.

Chances are it's completely harmless. I wouldn't bet my life on it, though.


You can use seccomp on Linux to isolate it. Seccomp is a Linux feature which filters system calls. There are two modes for seccomp, mode 1 and mode 2. Seccomp mode 1 is the most strict mode. When a program enables this mode, it is limited to using only four hardcoded syscalls: read(), write(), exit(), and rt_sigreturn(). Mode 2 is more complex, and uses a userspace-generated BPF filter to specify a custom whitelist of syscalls and syscall arguments. For a very simple piece of shellcode, you would only need mode 1.

Activating mode 1 seccomp is simple. Taken from another answer I wrote on another StackExchange site, a sample program that securely executes a function that returns 42 in bytecode:

#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <linux/seccomp.h>

/* "mov al,42; ret" aka "return 42" */
static const unsigned char code[] = "\xb0\x2a\xc3";

int main(void)
{
    int fd[2], ret;

    /* spawn child process, connected by a pipe */
    pipe(fd);
    if (fork() == 0) {
        close(fd[0]);

        /* enter mode 1 seccomp and execute untrusted bytecode */
        prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
        ret = (*(uint8_t(*)())code)();

        /* send result over pipe, and exit */
        write(fd[1], &ret, sizeof(ret));
        syscall(SYS_exit, 0);
    } else {
        close(fd[1]);

        /* read the result from the pipe, and print it */
        read(fd[0], &ret, sizeof(ret));
        printf("untrusted bytecode returned %d\n", ret);
        return 0;
    }
}

You would want to replace code[] with the shellcode you want to test.

You mentioned that there is one syscall to time(). On most Linux systems, this is not a true syscall, but a vDSO. If it is actually a direct syscall, you would need to use mode 2 seccomp and explicitly whitelist it. For this, you would want to use libseccomp to abstract away the complexity.

forest
  • 64,616
  • 20
  • 206
  • 257
  • This is an interview question, so I know it just obfuscates a string based on the current time, and there should be no further exploit, but I would rather treat it as unknown code. It's mostly to see how I think about RE, and one of my main tools is dynamic analysis. It would also make it easier to validate the results of my static analysis. – comp.sci.intern Nov 05 '18 at 17:49