這是一篇一年多以前的技術文章,但是裡面提到的方法在今天依舊不過時。希望這篇文章能給大家在物聯網

(IoT)安全方面帶來一些新的思路。

如果你對IoT安全感興趣的話,可以移步我近期發布的這些文章和回答:

知道創宇 雲安全:硬核分享|探針盒子?不用怕!手把手教你打造專屬隱私保護工具?

zhuanlan.zhihu.com
圖標
一個黑客能用一台手機做到什麼事情??

www.zhihu.com
圖標

--------正文分割線--------

作者:fenix@知道創宇404實驗室

原文鏈接:攝像頭漏洞挖掘入門教程(固件篇)

0x00 引言

據 IT 研究與顧問諮詢公司 Gartner 預測,2017 年全球物聯網設備數量將達到 84 億,比 2016 年的 64 億增長31%,而全球人口數量為 75 億。2020 年物聯網設備數量將達到 204 億。

而與如此快的發展速度相對應的,物聯網的安全問題也日趨凸顯,尤其是網路攝像頭、路由器等常見設備。我們可以從以下兩個案例大致感受一下物聯網設備嚴峻的安全形勢。

  • 抓住「新代碼」的影子 —— 基於 GoAhead 系列網路攝像頭多個漏洞分析
  • 全球 2.5 萬網路攝像機被黑,用於構建 DDOS 攻擊殭屍網路

物聯網設備數量的快速增長和其安全性的嚴重滯後形成了鮮明對比。同時也給惡意攻擊者和安全研究人員提供了新的土壤,這場正邪的博弈在新的戰場上正激烈上演。

這是一篇詳細的入門級別的教程,獻給眾多想入門智能設備安全的愛好者們。(本文完成於2017年,時隔一年對外發布。)

0x01 概述

1.0 固件及其常見獲取方式

固件(Firmware)就是寫入 EROM (可擦寫只讀存儲器)或 EEPROM(電可擦可編程只讀存儲器)中的程序。特殊的,對於市面上大部分的路由器和攝像頭來說,固件就是電路板上的 25 系列 Flash 晶元中的程序,其中存放著嵌入式操作系統,通常是 Linux 系統。

獲取固件是分析挖掘固件漏洞的前提,本文將以攝像頭為例,介紹如何 Dump Flash 晶元中的固件以及獲取固件之後的一些玩法思路。

通常情況下,有以下幾種獲取固件的途徑。

本文涉及後兩種方式提取固件的方式。

0x02 概念拓展

在開始正式的固件提取之前,先來熟悉幾個基礎概念。

2.0 串口和串口通信

串口(Serial port)又稱「序列埠」,主要用於串列式逐位數據傳輸。

UART(Universal Asynchronous Receiver/Transmitter) 是一種非同步串口通信協議。串口遵循 UART 協議按位(bit)非同步發送和接收位元組,通常情況下需要連接三對針腳,連線方式如下所示(圖片來自網路):

上圖中,TX 為接收端,RX 為傳輸端,GND 為接地端。按照圖示方式連接板子的調試串口和 USB 轉 TTL 串口線,設置好波特率、數據位、停止位和奇偶校驗等重要參數後,雙方就可以正常發送 ASCII 碼字元,從而進行非同步串口通信。

2.1 u-boot 引導

u-boot 是一種普遍用於嵌入式系統中的引導程序,它在操作系統運行之前執行,用來初始化軟硬體環境,並最終啟動系統內核。

0x03 通過調試串口進入系統

3.0 研究對象

本節我們將從一款無線監控攝像頭入手,講解如何通過調試串口獲取系統的 Shell。

使用 nmap 探測該攝像頭的開放埠及服務,結果如下

Host is up (0.0031s latency).
Not shown: 996 closed ports
PORT STATE SERVICE VERSION
100/tcp open http Mongoose httpd
554/tcp open rtsp
1935/tcp open tcpwrapped
100100/tcp open soap gSOAP 2.8

監聽在 100 埠的 Mongoose 是一個嵌入式的 Web 伺服器,gSOAP 是一個跨平台的,用於開發 Web Service 服務端和客戶端的工具。RTSP(Real Time Streaming Protocol),實時流傳輸協議,是 TCP/IP 協議體系中的一個應用層協議,該協議定義了一對多應用程序如何有效地通過 IP 網路傳送多媒體數據。

之後可以通過 Fidderwireshark 等工具對服務進行抓包分析,然而這不是我們今天的重點。下面我們將從硬體的角度去分析。

3.1 需要的工具

  • USB 轉 TTL 串口線
  • 電烙鐵
  • 螺絲刀
  • ...

3.2 UART 藏哪了

製造路由器、攝像頭等設備的廠商通常會在設備上留下調試串口方便開發或售後過程中的調試,為了和設備進行通信,我們首先需要找到這些 "後門"。用工具將攝像頭拆開,根據主板上晶元上的型號可以識別出晶元的用途。如圖,我們找到了處理器和存儲器晶元的位置,處理器是國科 IPC 晶元 GK7102,存儲器晶元是 25 系列 flash 晶元 IC25LP128 。主板上空閑的介面有三個(右圖),左下、右下、右下偏上,經過測試,左下那個是 4 針 debug 串口(波特率 115200),串口的第一個針腳為 Tx,第三個針腳為 Rx,分別與 USB-轉-TTLRxTx 連接(USB 轉 TTL 串口線和主板由同一個 Hub 供電,VCC 相差不大,沒有連接 GND)。

至於如何找到設備上的調試串口,可參考 reverse-engineering-serial-ports,此處不再贅述。

minicom 是一款 Linux 平台上的串口工具,在控制台鍵入以下命令和串口進行通信。

# Use the following Bash code:

minicom -D /dev/ttyUSB0

在這步操作的時候很容易遇到許可權的問題,介紹一個很粗暴的方法。

sudo chmod 777 /dev/ttyUSB0

3.3 嵌入式系統啟動流程

筆記本正確連接主板串口,供電後,在終端可以看到以下系統啟動過程中的調試信息。

Flash 晶元的分區信息如下

開機後系統啟動了以下服務,可能是攝像頭服務的主進程。

系統啟動完成後,提供了Shell 的登陸界面。

通過觀察啟動流程,我們已經獲得了很多有用的信息,對 u-boot 如何引導系統的啟動也有了一個大致的認識。

最後,我們嘗試使用弱密碼獲取系統的 Shell,遺憾的是,經過多次嘗試,均已失敗告終。

3.4 登陸繞過

如果你使用過 Linux 系統,或多或少的經歷過忘記系統密碼導致無法進入系統的尷尬境地。我們的解決方案也堪稱簡單粗暴,直接進入 grub 引導修改密碼。所以,如果設備觸手可及,幾乎不存在進不入系統的問題。

在攝像頭這種運行著嵌入式 Linux 操作系統的設備上,也有一個類似 grub 的存在,它就是 u-boot

重啟設備,根據提示鍵入組合鍵進入到 u-boot 命令行界面。

u-boot 命令行內置了很多常用命令供我們使用,鍵入 h 查看幫助。

通過 printenv 列印出 u-boot 傳遞給內核的參數信息。

從部分參數的內容可以看到 u-boot 引導程序是如何移交控制權給內核的。

  • 首先為內核設置啟動參數

console=${consoledev},${baudrate} noinitrd mem=${mem} rw ${rootfstype} init=linuxrc

  • 將內核從 Flash 載入到內存中
  • 跳轉到內存中內核的起始地址並執行

我們來重點看下啟動參數的 init 欄位。

init 欄位設置內核執行的初始化進程名,比如上面的 linuxrc,它是位於文件系統根目錄下的一段程序代碼,負責後續的系統初始化工作。

是否可以直接修改 init=/bin/sh 從而實現在系統未初始化完成的時候訪問根文件系統呢?我們不妨試一下,在 u-boot 命令行中修改參數 sfbootinit 欄位的值為 /bin/sh並保存,修改後效果如下。(修改前做好參數的備份)

console=${consoledev},${baudrate} noinitrd mem=${mem} rw ${rootfstype} init=/bin/sh

重啟設備,正如我們所猜想的,修改內核執行的初始進程,我們成功獲得了一個 Shell

由於沒有經過 linuxrc 的初始化過程,這樣獲得的 Shell 功能是很受限的。在該 shell 下編輯 /etc/shadow 文件,擦除或者破解 root 用戶的密碼,重啟到 u-boot 命令行界面中修改回原來的啟動參數並保存,再次重啟到 Shell 登陸界面,即可獲得一個具有完整功能的 Shell。

3.5 打包上傳固件

經過上面的步驟,我們已經可以登錄到一個功能完整的 Shell,使用 tartftp 命令打包上傳根文件系統到 tftp 伺服器即可。

3.6 其他技巧

u-boot 中提供了相關命令操作 Flash 晶元,所以也可以按照如下方式提取固件。(這種 cat 內存的方式只是一種思路,速度是內傷)

0x04 暴力讀寫固件存儲晶元解鎖新功能

本小節我們以另一款基於 gSOAP 協議的攝像頭為例(固件存儲晶元型號 MX25LP128),介紹如何用編程器讀寫 Flash 晶元,從而打開該攝像頭的 telnet 服務。

4.0 需要準備的工具

  • 25 系列晶元編程器
  • 電洛鐵
  • ...

4.1 讀取固件

MX25L128 這款 25 系列 Flash 晶元可以直接在線讀取,用 夾子 夾住 Flash 晶元,連接編程器即可讀取其中的固件。

點擊 智能識別SmartID,晶元型號識別成功後點擊 讀取 Read ,最後保存成文件即可。如下圖,讀取過程非常順利。

4.2 固件解壓

binwalk 是 devttys0 大神開發的一款固件分析工具,強烈推薦使用 Github 上的教程安裝,直接 apt-get 安裝會缺少很多依賴。

使用 binwalk 查看固件結構

內核編譯(make)之後會生成兩個文件,一個 Image,一個 zImage,其中 Image 為內核映像文件,而 zImage為內核的一種映像壓縮文件。

那麼 uImage 又是什麼的?它是 uboot 專用的映像文件,它是在 zImage 之前加上一個長度為 64 位元組的頭部,說明這個內核的版本、載入位置、生成時間、大小等信息;其 0x40 之後與 zImage 沒有區別。

固件使用的是 squashfs 文件系統,它是一套供 Linux 核心使用的 GPL 開源只讀壓縮文件系統。所以設備正常運行的時候是不能對固件進行修改的,在前面那部分,我們從串口進去通過修改內核的初始進程的方式進入系統,是由於系統尚未初始化完成,從而獲得了對文件系統的讀寫許可權。

在固件的後一部分,包含一個可以寫入的區域。一個 JFFS2 文件系統,它是在快閃記憶體上使用非常廣泛的讀/寫文件系統,設備運行過程中修改過的配置信息和其他數據將被寫入這個文件系統中。

squashfs 文件系統開始於 0x3100000, 大小為 6963644 位元組, 用 dd 命令提取該文件系統,用 unsquashfs 命令解壓。

4.3 解鎖功能

熟悉文件系統結構和已有的命令

很明顯,該固件的 Shell 是基於 busybox 提供的。從 file 指令的結果可以判斷該攝像頭是 32位 ARM 指令架構。

這個 busybox 是靜態鏈接的,不依賴其他的庫文件。可以直接利用 qemu-arm 模擬運行。

當然,我們也可以搭建一個 qemu 虛擬機。

在這個網站下載 qemu 虛擬機鏡像文件,然後按照如下方式啟動虛擬機。

現在我們已經可以確定目標文件系統是存在 telnetd 命令的。在根目錄下的 boot.sh 文件末尾添加以下內容,使設備在開啟時自動啟動 telnet 服務。

4.4 重新封印

現在,對文件系統的簡單修改已經完成了,我們該如何重新打包固件,以便重新刷回到設備呢?

還是從固件結構入手,如下

我們自定義的只是中間的文件系統部分。即 0x3100000 - 0xB00000 這一段。同時,這一段的長度並不等於 squashfs 文件系統的大小 6963644 位元組,squashfs 文件系統末至下一段開始之前有一段 0xff的填充部分。

從 uImage 頭信息可以看到,image size2217456, 而 squashfs 文件系統的起始位置為 3670016,沒有對 squashfs 文件系統做 CRC 檢驗。

根據以上結論判斷,我們只需要在不改變原始固件結構的前提下,將修改後的文件系統重新打包成固件。

利用 cat 將各段連接起來

4.5 刷回

Cheers,重新打包完成。利用編程器將修改後的固件離線刷入固件存儲晶元即可。(在線刷各種坑,建議離線寫入)

4.6 成果

可以看到,我們成功開啟了該攝像頭的 telnet 服務。

0x05 總結

對智能設備的軟硬體有足夠的了解是深入挖掘設備漏洞的基礎。本文是在對攝像頭等物聯網設備研究過程中的一些經驗總結,希望對大家有所幫助。


本文由 Seebug Paper 發布,如需轉載請註明來源。

歡迎關注我和專欄,我將定期搬運技術文章~

也歡迎訪問我們:知道創宇雲安全


推薦閱讀:
相关文章