In Tactical Network Solutions' Intro to Embedded Device Exploitation class, we use the D-Link DIR-815 for the practical exercises since there are tons of great 0-days for the students to find. The last time we taught the class, I thought I'd try my hand at finding a new one. Twenty minutes in, voila! Command injection in a single multicast packet!
The DIR-815 has a single binary executable, /htdocs/cgibin, that is responsible for handling most, if not all, HTTP requests. I found a symlink to cgibin called 'ssdpcgi':
zach@endor: dir-815-reva1/v1.00/squashfs-root/htdocs (0) $ ls -l upnp/ssdpcgi lrwxrwxrwx 1 zach wheel 14 Jan 9 13:43 upnp/ssdpcgi -> /htdocs/cgibin
If we disassemble cgibin and look at ssdpcgi_main(), we see it executing a shell script called "/etc/scripts/upnp/M-SEARCH.sh".
A shell script gets excecuted with the contents of the ST field as an argument. |
The contents of the M-SEARCH packet get turned into shell arguments. If we can get one of the arguments to be a string inside backticks, the string gets executed by system()'s 'sh -c' and its output gets handed to M-SEARCH.sh as arguments.
So what if we send an M-SEARCH packet with the ST: field containing the string `reboot`?
M-SEARCH * HTTP/1.1 HOST:239.255.255.250:1900 ST:uuid:`reboot` MX:2 MAN:"ssdp:discover"
If we send that packet to the 239.255.255.250 multicast address, on UDP port 1900, our D-Link router reboots! Nice!
But rebooting routers is bullshit. Root or it didn't happen, right? Okay, no problem. D-Link routers generally come with a telnet server onboard, so lets use the command injection to fire it up:
Getting root via command injection on the D-Link DIR-815 wireless router |
Here's some proof-of-concept python code to try out.