Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
My last SLAE assignment #5 solution is my Metasploit exec analysis.
One more shellcode to analyze, and one more tool to use.
In this case, I will be analyzing the exec shellcode using libemu.
For more information on installation and configuration, you can see my earlier blog post.
I was originally planning on analyzing the chmod shellcode, but I ran into a few issues. It turns out that libemu chokes/breaks on a lot of the Metasploit payloads. If you have any ideas what might cause this, then I’d love to know!
Since I’ve already written my bind/reverse shells, I figured execve is good enough to show off some libemu usage.
For the exec payload, we just need to set a file to change and the file mode.
doyler@slae:~/slae/_exam/msf_analysis$ msfvenom -p linux/x86/exec --payload-options Options for payload/linux/x86/exec: Name: Linux Execute Command Module: payload/linux/x86/exec Platform: Linux Arch: x86 Needs Admin: No Total size: 36 Rank: Normal Provided by: vlad902Basic options: Name Current Setting Required Description ---- --------------- -------- ----------- CMD yes The command string to execute Description: Execute an arbitrary command
In this case, I decided to cat /etc/passwd, similar to my earlier post.
With my options selected, I generated the payload that I wanted.
doyler@slae:~/slae/_exam/msf_analysis$ msfvenom -p linux/x86/exec CMD='cat /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: 51 bytes Final size of c file: 240 bytes unsigned char buf[] = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68" "\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x10\x00\x00\x00\x63" "\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x00" "\x57\x53\x89\xe1\xcd\x80";
Next, I added the payload to my wrapper program and executed. As usual, the shellcode length is incorrect due to null bytes. That said, the passwd file properly printed!
doyler@slae:~/slae/_exam/msf_analysis$ gcc -o shellcode -z execstack -fno-stack-protector shellcode.c doyler@slae:~/slae/_exam/msf_analysis$ ./shellcode Shellcode Length: 15 root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh
First, I ran the shellcode through libemu’s sctest binary.
The -vvv flag increases the verbosity, -S reads the shellcode from stdin, -s runs the code up to 100k steps, and -G outputs the call graph to a dot file.
doyler@slae:~/libemu/tools/sctest$ msfvenom -p linux/x86/exec CMD='cat /etc/passwd' -f raw | sudo ./sctest -vvv -Ss 100000 -G metasploit_exec.dot graph file metasploit_exec.dot verbose = 3 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: 51 bytes
As you can see, Libemu tracks operation execution, and the state of each register.
The following instructions get the registers ready for the system call.
[emu 0x0x8997090 debug ] cpu state eip=0x00417000 [emu 0x0x8997090 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000 [emu 0x0x8997090 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] cpu state eip=0x00417000 [emu 0x0x8997090 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000 [emu 0x0x8997090 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 6A0B push byte 0xb [emu 0x0x8997090 debug ] cpu state eip=0x00417002 [emu 0x0x8997090 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000 [emu 0x0x8997090 debug ] esp=0x00416fca ebp=0x00000000 esi=0x00000000 edi=0x00000000 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 58 pop eax [emu 0x0x8997090 debug ] cpu state eip=0x00417003 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00000000 [emu 0x0x8997090 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 99 cwd [emu 0x0x8997090 debug ] cpu state eip=0x00417004 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00000000 [emu 0x0x8997090 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 52 push edx [emu 0x0x8997090 debug ] cpu state eip=0x00417005 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00000000 [emu 0x0x8997090 debug ] esp=0x00416fca ebp=0x00000000 esi=0x00000000 edi=0x00000000 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 66682D63 push word 0x632d [emu 0x0x8997090 debug ] cpu state eip=0x00417009 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00000000 [emu 0x0x8997090 debug ] esp=0x00416fc8 ebp=0x00000000 esi=0x00000000 edi=0x00000000 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 89E7 mov edi,esp [emu 0x0x8997090 debug ] cpu state eip=0x0041700b [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00000000 [emu 0x0x8997090 debug ] esp=0x00416fc8 ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 682F736800 push dword 0x68732f [emu 0x0x8997090 debug ] cpu state eip=0x00417010 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00000000 [emu 0x0x8997090 debug ] esp=0x00416fc4 ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 682F62696E push dword 0x6e69622f [emu 0x0x8997090 debug ] cpu state eip=0x00417015 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00000000 [emu 0x0x8997090 debug ] esp=0x00416fc0 ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 89E3 mov ebx,esp [emu 0x0x8997090 debug ] cpu state eip=0x00417017 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00416fc0 [emu 0x0x8997090 debug ] esp=0x00416fc0 ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 52 push edx [emu 0x0x8997090 debug ] cpu state eip=0x00417018 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00416fc0 [emu 0x0x8997090 debug ] esp=0x00416fbc ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] E8 call 0x1 [emu 0x0x8997090 debug ] cpu state eip=0x0041702d [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00416fc0 [emu 0x0x8997090 debug ] esp=0x00416fb8 ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 57 push edi [emu 0x0x8997090 debug ] cpu state eip=0x0041702e [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00416fc0 [emu 0x0x8997090 debug ] esp=0x00416fb4 ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 53 push ebx [emu 0x0x8997090 debug ] cpu state eip=0x0041702f [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00000000 edx=0x00000000 ebx=0x00416fc0 [emu 0x0x8997090 debug ] esp=0x00416fb0 ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 89E1 mov ecx,esp
As you can see, the registers are all properly set before the program executes the syscall.
[emu 0x0x8997090 debug ] cpu state eip=0x00417031 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00416fb0 edx=0x00000000 ebx=0x00416fc0 [emu 0x0x8997090 debug ] esp=0x00416fb0 ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] CD80 int 0x80 execve int execve (const char *dateiname=00416fc0={/bin/sh}, const char * argv[], const char *envp[]); [emu 0x0x8997090 debug ] cpu state eip=0x00417033 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00416fb0 edx=0x00000000 ebx=0x00416fc0 [emu 0x0x8997090 debug ] esp=0x00416fb0 ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: [emu 0x0x8997090 debug ] 0000 add [eax],al cpu error error accessing 0x00000004 not mapped stepcount 15
For your reference, this is how the registers look before execution:
To verify this, I also ran a quick strace on my binary.
doyler@slae:~/slae/_exam/msf_analysis$ strace -e execve ./shellcode execve("./shellcode", ["./shellcode"], [/* 36 vars */]) = 0 Shellcode Length: 53 execve("/bin//sh", ["/bin//sh", "-c", "cat /etc/passwd"], [/* 0 vars */]) = 0 root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh
Once the execution is complete, libemu begins generating the dot file.
copying vertexes optimizing graph vertex 0x89ee3d8 going forwards from 0x89ee3d8 -> vertex 0x89f0578 -> vertex 0x89f0788 -> vertex 0x89f0968 -> vertex 0x89f0a48 -> vertex 0x89f0d00 -> vertex 0x89f0dd0 -> vertex 0x89f0f38 -> vertex 0x89f1130 -> vertex 0x89f1318 -> vertex 0x89f1490 -> vertex 0x89f1608 -> vertex 0x89f1780 -> vertex 0x89f18f8 copying edges for 0x89f18f8 -> 0x89f4c40 vertex 0x89f1a70 going forwards from 0x89f1a70 copying edges for 0x89f1a70 vertex 0x89f1ef8 going forwards from 0x89f1ef8 copying edges for 0x89f1ef8
Finally, libemu also generates some pseudo-code! This is incredibly handy to see the program and methods. Additionally, it is useful for converting shellcode back into an actual C program.
[emu 0x0x8997090 debug ] cpu state eip=0x00417035 [emu 0x0x8997090 debug ] eax=0x0000000b ecx=0x00416fb0 edx=0x00000000 ebx=0x00416fc0 [emu 0x0x8997090 debug ] esp=0x00416fb0 ebp=0x00000000 esi=0x00000000 edi=0x00416fc8 [emu 0x0x8997090 debug ] Flags: int execve ( const char * dateiname = 0x00416fc0 => = "/bin/sh"; const char * argv[] = [ = 0x00416fb0 => = 0x00416fc0 => = "/bin/sh"; = 0x00416fb4 => = 0x00416fc8 => = "-c"; = 0x00416fb8 => = 0x0041701d => = "cat /etc/passwd"; = 0x00000000 => none; ]; const char * envp[] = 0x00000000 => none; ) = 0;
Once libemu completed its execution, I used the `dot` command to convert the dot file into a png
doyler@slae:~/libemu/tools/sctest$ dot metasploit_exec.dot -Tpng -o metasploit_exec.png
As you can see, libemu also generates an awesome little control flow graph! While this one isn’t super complex, they can get pretty in-depth.
In the case of this shellcode, there were five null bytes. Three were for the relative call, one was in the /bin/sh string, and one was at the end of /etc/passwd.
Unfortunately, I ended up increasing the length of the shellcode by two bytes. This was due to the JMP-CALL gadget adding one byte, and my null termination of /etc/passwd adding another.
> doyler@slae:~/slae/_exam/msf_analysis$ for i in $(objdump -d exec |grep "^ " |cut -f2); do echo -n '\x'$i; done; echo \x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\xeb\x06\x57\x53\x89\xe1\xcd\x80\xe8\xf5\xff\xff\xff\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64 doyler@slae:~/slae/_exam/msf_analysis$ vi shellcode.c doyler@slae:~/slae/_exam/msf_analysis$ gcc -o shellcode -z execstack -fno-stack-protector shellcode.c doyler@slae:~/slae/_exam/msf_analysis$ ./shellcode Shellcode Length: 53 root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh
You can find my version of the shellcode below.
; Filename: metasploit_exec.nasm ; Author: Ray Doyle (@doylersec) ; Website: https://www.doyler.net ; ; Purpose: SLAE Exam Assignment #5 - Metasploit exec shellcode (Linux/x86) for `cat /etc/passwd` with no null bytes global _start section .text _start: push 0xb pop eax cdq push edx push word 0x632d mov edi,esp push edx push 0x68732f2f push 0x6e69622f mov ebx, esp push edx pre_exec: jmp call_exec exec: push edi push ebx mov ecx,esp int 0x80 call_exec: call exec command: db "cat /etc/passwd"
I wish libemu worked on more of the Metasploit shellcodes, but this is still a great tool to use.
This concludes assignment #5, so only two more to go!
Next week is polymorphic shellcode, so back to at least modifying some assembly.
Finally, you can find the code and updates in my GitHub repository.
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert Certification:
http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert
Student-ID: SLAE-1212
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he’s done it all. To show for it, he has obtained an OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!
He currently serves as a Senior Staff Adversarial Engineer for Avalara, and his previous position was a Principal Penetration Testing Consultant for Secureworks.
This page contains links to products that I may receive compensation from at no additional cost to you. View my Affiliate Disclosure page here. As an Amazon Associate, I earn from qualifying purchases.