Assignment Task:
Take up at least 3 shellcode samples created using msfvenom for linux/x86
Use GDB/Ndisasm/Libemu to dissect the functionality of the shellcode
Present your analysis
Shellcode chosen:
[code lang="c"]
linux/x86/read_file
[/code]
Shellcode options:
Command to generate shellcode:
[code lang="c"]
msfvenom -p linux/x86/read_file PATH=/etc/issue -b '\x00' -f c
[/code]
Generated shellcode:
[code lang="c"]
"\xda\xc2\xd9\x74\x24\xf4\x58\x29\xc9\xb1\x13\xbe\xf6\xd9\x40"
"\x85\x31\x70\x17\x83\xe8\xfc\x03\x86\xca\xa2\x70\x8d\xdb\x9a"
"\x7e\x51\x24\xdb\xdb\x60\xed\x16\x5b\x0b\x2e\x10\x5f\x0b\xb1"
"\x61\xe9\xec\x38\x98\x53\xf2\x2a\x5b\xa4\x3f\xca\xd2\x66\x07"
"\xcf\xe4\x66\x77\x6b\xe5\x66\x77\x8b\x2b\xe6\xcf\x8a\xb3\xe7"
"\x2f\x36\xb3\xe7\x2f\x48\x79\x67\xc7\x8d\x7e\x97\xe8\x21\xe4"
"\x1c\x75\x11\x8f\xaf\x0a\x18\x2a\x50";
[/code]
Contents of file /etc/issue:
Testing shellcode with run_shellcode.c
Let's analyze the shellcode with gdb:
Placed a breakpoint at code variable, defined hook-stop and issued run command:
We have hit our breakpoint and this is the state of CPU registers:
Examining the contents at memory loaction 0x0804a040 (i.e. where EIP is pointing to at present):
We are at the begining of our shellcode. We step into the code few times to let the decoder work:
We have entered a loop. Placing the breakpoint at 0x0804a05b (the next instruction after loop) and continuing the execution of the program:
Disassembling 70 bytes from eip. This is our decoded shellcode:
[code lang="c"]
0x0804a05b <code+27>: jmp 0x804a093 <code+83>
0x0804a05d <code+29>: mov eax,0x5
0x0804a062 <code+34>: pop ebx
0x0804a063 <code+35>: xor ecx,ecx
0x0804a065 <code+37>: int 0x80
[/code]
The above code executes syscall number 0x5 (05 in decimal). This syscall number represents (open):
This syscall takes in two arguments as shown below:
The above code stores the string '/etc/issue' on the stack and pops it into ebx using the jump call technique. It sets the mode to 0 (stored in ecx) and then executes the syscall
[code lang="c"]
0x0804a067 <code+39>: mov ebx,eax
0x0804a069 <code+41>: mov eax,0x3
0x0804a06e <code+46>: mov edi,esp
0x0804a070 <code+48>: mov ecx,edi
0x0804a072 <code+50>: mov edx,0x1000
0x0804a077 <code+55>: int 0x80
[/code]
The above code executes syscall number 0x3 (03 in decimal). This syscall number represents (read):
This syscall takes in three arguments as shown below:
The above code stores the file descriptor, returned by open syscall, in ebx. It then stores the current value of esp into edi and moves it to ecx (buffer). It then stores the value of 0x1000 in edx (represents the length of the buffer to read). Finally, it executes the read syscall.
[code lang="c"]
0x0804a079 <code+57>: mov edx,eax
0x0804a07b <code+59>: mov eax,0x4
0x0804a080 <code+64>: mov ebx,0x1
0x0804a085 <code+69>: int 0x80
[/code]
The above code executes the syscall number 0x4 (04 in decimal). This syscall number represents (write)
This syscall takes in three arguments as shown below:
The above code writes the buffer read by the read() syscall to STDOUT. It first stores the value returned by read() syscall in edx. It then stores the syscall number in eax, stores the value 0x1 (which is the file descriptor for STDOUT) in ebx and executes the syscall. Since ecx already points to the buffer it need not be set.
[code lang="c"]
0x0804a087 <code+71>: mov eax,0x1
0x0804a08c <code+76>: mov ebx,0x0
0x0804a091 <code+81>: int 0x80
[/code]
These instructions execute the exit syscall.
[code lang="c"]
0x0804a098 <code+88>: das
0x0804a099 <code+89>: gs
0x0804a09a <code+90>: je 0x804a0ff
0x0804a09c <code+92>: das
0x0804a09d <code+93>: imul esi,DWORD PTR [ebx+0x73],0x6575
[/code]
As can be seen from the above image, instructions from 0x0804a098 to 0x0804a09d are hex values for the string '/etc/issue'. These hex values have been translated by gdb as instructions.
Github repository for this assignment: Assignment 5/5-3