IoT设备硬件攻击技术
0x01 总线与接口概述
1.1 UART
概述
UART(Universal Asynchronous Receiver/Transmitter)是一种常见的串行通信协议,广泛用于嵌入式设备中进行调试和数据传输。它通过两根信号线(TX和RX)实现异步通信。UART协议的中,包含起始位、数据位、校验位、停止位。
- 接口识别
- 使用万用表或逻辑分析仪检测设备上的测试点,寻找电压为3.3V或5V的引脚。
- 常见的UART引脚包括:TX(发送)、RX(接收)、GND(地线)和VCC(电源)。上电时,由于程序通常会输出调试信息,导致TX上会产生电压波动,所以这时可以查看接口波形,电压幅度发生较大变化的引脚即为TX,电压幅度变化较小的引脚则为RX。
- 波特率探测
- 使用工具(如
minicom
、screen
或Arduino
)尝试不同的波特率(如9600、115200等)与设备通信。 - 自动化工具如
baudrate.py
可以快速探测正确的波特率。
- 使用工具(如
- 调试访问
- 通过UART接口获取设备的调试Shell,可能直接进入系统命令行。
- 利用UART日志分析设备启动过程,提取敏感信息(如引导加载程序密码、加密密钥等)。
- 防护绕过
- 修改启动参数(如U-Boot参数)以禁用安全启动或加载自定义固件。
- 通过UART注入恶意命令或脚本。
1.2 SPI && I2C
概述
SPI(Serial Peripheral Interface)和I2C(Inter-Integrated Circuit)是两种常用的同步串行通信协议,主要用于设备内部芯片之间的数据交换。
SPI
- 特点:高速、全双工通信,通常需要4根线(MOSI、MISO、SCLK、CS)。
- 应用场景:Flash存储器、传感器、显示屏等。
I2C
- 特点:低速、半双工通信,仅需两根线(SDA、SCL)。
- 应用场景:低功耗设备、传感器、EEPROM等。
攻击技术
- 接口识别
- 使用逻辑分析仪或示波器检测信号线,确定SPI/I2C通信的时钟频率和数据模式。
- 使用Attify Bridge等工具连接SPI闪存芯片后,可实现转储固件。
- 数据嗅探
- 使用Bus Pirate、Logic Analyzer等工具捕获SPI/I2C总线上的数据流。
- 解码捕获的数据包,提取敏感信息(如配置参数、加密密钥)。
- 固件提取
- 通过SPI接口直接读取Flash芯片中的固件。
- 使用专用工具(如
flashrom
)与SPI Flash芯片通信,提取或修改固件。
- 协议漏洞利用
- 针对I2C协议的地址冲突或缺乏身份验证机制,伪造设备身份进行中间人攻击。
- 利用SPI协议的简单性,篡改数据流或注入恶意指令。
1.3 JTAG
概述
JTAG(Joint Test Action Group)是一种标准化的硬件调试接口,最初用于电路板测试,后来被广泛应用于嵌入式系统的调试和编程。
其中4个最重要的引脚为**TCK(Test Clock)**JTAG的核心时钟信号,同步所有操作;**TDI(Test Data In)**数据输入通道,用于发送指令和数据;**TDO(Test Data Out)**数据输出通道,用于读取设备信息;**TMS(Test Mode Select)**控制JTAG状态机模式切换的核心信号。
目前JTAG接口有两种连接标准:14针接口及20针接口。接口定义如下所示。
14针接口定义:
引脚定义 | 引脚功能 |
---|---|
1、13 | VCC,连接电源输入 |
2、4、6、8、10、14 | GND,连接电源地 |
3 | NTRST系统复位信号 |
5 | TDI测试数据串行输入 |
7 | TMS测试模式选择 |
9 | TCK测试时钟信号 |
11 | TDO测试数据串行输出 |
12 | 未连接 |
20针接口定义:
引脚定义 | 引脚功能 |
---|---|
1 | 目标板参考电压 |
2 | VCC 电源输入 |
3 | NTRST测试系统复位信号 |
4、6、8、10、12、14、16、18、20 | GND 连接电源地 |
5 | TDI测试数据串行输入 |
7 | TMS测试模式选择 |
9 | TCK测试时钟信号 |
11 | RTCK测试时钟返回信号 |
13 | TDO测试数据串行输出 |
15 | NRESET目标系统复位信号 |
17、19 | 未连接 |
对于开发板上元器件的JTAG接口,较多采用MOLEX的8针连接器,其体积较小,便于集成电路设计且功能齐全,其接口一般如下所示:
引脚定义 | 引脚信号 |
---|---|
1 | +3V3 |
2 | NTRST |
3、6 | 3V3GND |
4 | TDO |
5 | TDI |
7 | TMS |
8 | TCK |
攻击技术
-
接口识别
- JTAG接口通常由多个引脚组成,包括TCK(时钟)、TDI(数据输入)、TDO(数据输出)、TMS(模式选择)和GND。
- 使用JTAGulator或Flyswatter等工具扫描设备上的测试点,定位JTAG接口。
-
边界扫描
- 利用JTAG的边界扫描功能,读取或控制设备的引脚状态。
- 分析芯片内部寄存器,提取运行时数据或修改关键参数。
-
固件提取与调试
- 通过JTAG接口连接调试器(如OpenOCD、Segger J-Link),直接读取设备内存中的固件。
- 在运行时暂停CPU,分析寄存器和堆栈内容,查找漏洞或提取敏感信息。
-
安全防护绕过
- 禁用设备的安全启动功能,加载未签名的固件。
- 修改设备的启动流程,跳过身份验证或加密检查。
-
防护措施
- 设备厂商可以通过禁用JTAG接口、熔断保险丝或加密调试通道来防止未经授权的访问。
- 攻击者可能需要物理手段(如重新焊接芯片)绕过这些限制。
0x02 接口交互
2.1 UART接口交互与漏洞利用
UART Shell 访问步骤
- 识别接口 :根据 1.1 描述的方法,确认设备的 TX(发送)和 RX(接收)引脚。
- 硬件连接 :使用 USB 转 TTL 模块将设备连接到电脑。
- 波特率探测 :运行
baudrate.py
工具,自动检测正确的波特率。成功识别后,按下Ctrl+C
中断。 - 进入终端 :工具会自动启动
minicom
,进入串口通信界面。 - Shell 访问 :如果设备通过 UART 提供了 Shell 访问权限,只需按下回车键即可进入 Shell。
NAND故障注入
以下内容来自书籍《IOT PENETRATION TESTING COOKBOOK》
顾名思义,噪声干扰就是在测试的系统中引入错误。这一过程可以通过多种方式完成,并且已经有很多论文以及研究文献对此进行了探讨。噪声干扰的目的在于打乱 bootloader,更改引导参数或敏感数据,在引导过程中我们可以自定义参数以绕过系统的检测。可以通过 shell 来启动 UART 控制台,或者进入用户模式引导系统,上述两种操作都可以用来绕过验证。
测试流程
- NAND 噪声(NAND glitching),这将使设备中 NAND 闪存的一个 I/O 引脚从 GND 引脚短路。需要注意的是,短路操作的执行时机需要控制在 bootloader 已经引导并且需要进行内核引导时。(上电后一秒左右)
- 最后,如果线路成功,内核则会引导失败,用户进入到默认的 bootloader 命令行界面,提示用户输入命令,这时用户就能修改 bootloader 的参数了。
- 下面以一个实际案例介绍修改 bootloader 访问权限用户所能执行的操作,在引导参数中添加 single 参数后,用户即可进入单用户模式,从而绕过部分系统所要求的认证过程。
另一个例子:Nand Glitching Wink Hub For Root
参考链接:https://www.brettlischalk.com/posts/nand-glitching-wink-hub-for-root
Overview
During the Offensive Internet Of Things Exploitation course the instructor demonstrates a technique called a “NAND Glitch” on a Wink Connected Home Hub IoT device.
This technique allows a root shell to be acquired on a device which normally does not provide console access. This post outlines the process I used to replicate the NAND Glitch as well as discusses some of the “gotchas” that I encountered along the way.
Tools
The tools that I utilized to perform the NAND Glitch were:
- Wink Connected Home Hub
- Bus Pirate - v 3.6a
- Bus Pirate Cable
- Break Away Headers - Straight
- Ubuntu Virtual Machine
- Screen
- Soldering Iron / Solder
Steps
The steps that I performed to gain a root shell on the Wink Hub device are as follows:
- Disassemble the device
- Solder headers into the UART connections
- Hook up the Bus Pirate
- Use screen to setup the Bus Pirate for UART mode and various other configurations
- Use screen to connect to the Wink Hub over a UART terminal interface
- Plug in the Wink Hub
- Use a wire to short the 29th pin of the NAND flash chip to ground
- Change the boot arguments to use /bin/sh
- Reboot the hub
- Enjoy root access!
Disassembly
Disassembly of the Wink Hub is pretty straight forward. The device has 4 hex screws that need to be removed. Once these are removed there is 1 black circuit board that makes up the whole device. Pull the board out and begin the hacking fun.
Solder Headers
The Wink Hub circuit board does not have headers attached for UART serial interfacing but it does have the pin-outs marked. Simply solder some headers into the pin-outs using through-hole soldering and you’ll be set to connect to the device. When I did my soldering I hadn’t heard of a “Helping Hand Tool” so my soldered pins looked a bit crooked. This didn’t prevent me from getting a UART terminal connection but I learned that if I need to do more intricate soldering in the future, that one of these tools could really come in handy.
Hook Up The Bus Pirate
Hooking up the Bus Pirate is as simple as:
- Connect the USB cord from the Bus Pirate device to my laptop
- Connect the GND, MISO, and MOSI connections from the Bus Pirate to the appropriate TX, RX, and GND connections of the UART headers
- In VirtualBox, select the usb device that was connected
- Use
ls /dev/tty*
to list tty devices - Discover that
/dev/ttyUSB0
is the device that will be used
** NOTE: I encountered a bit of trouble / confusion with the cable. I didn’t know that there were actually different cables available with the colored wires organized in different orders. I eventually came across this Wiring Diagram which illustrated that the cable that I had purchased actually had the colors reversed from what I was seeing in other diagrams.
Use Screen to Configure Bus Pirate UART Connection
Once the Bus Pirate was connected, the next step was to configure the Bus Pirate. To configure the device I connected using the command:
sudo screen /dev/ttyUSB0 115200
Once connected, I was presented with a prompt for the Bus Pirate. I believe I actually received a black screen which required me to hit enter to actually see the prompt. Another thing I learned in this project is that serial work can be a little flaky. Through this prompt you configure the Bus Pirate to become a “bridge” which allows UART communication to pass thru the Bus Pirate and to the device you are communicating with.
In this prompt I used “m” to configure the mode of the Bus Pirate as UART. In this configuration wizard all of the defaults are selected except for a baudrate of 115200 and 3.3v as the voltage of the device.
After the UART mode was configured, I started a “Transparent UART Bridge” via the macro (1)
.
** NOTE: After setting this up and booting up the Wink Hub, the text on the screen would come out looking like garbage. I did a bunch of Googling and research and it seemed that I also had to set the baudrate using the “b” menu to 115200 prior to setting the mode to UART using the “m” option and going through the wizard. I don’t remember why I had to do this but that seemed to clear up the garbage output.
Short the NAND Flash
After the Bus Pirate is all configured and a serial screen connection is setup, the next step was to actually start up the Wink Hub and glitch the NAND chip. To perform the glitch I used a piece of wire with one end touching some of the metal chip housing, and the other end touching the 29th pin of the NAND flash. It took a few tries to get to work as I found that I had to create the short in less than a second after starting up the Wink Hub. Other articles I had found on the subject said to create the short after ~1 sec but I found that it needed to happen much sooner than that. As soon as the short worked, I would receive a terminal prompt after a kernel panic message.
Update Boot Args
At this point we have a shell but not a root shell. By executing printenv
we see that the arguments used during boot are:
bootargs=noinitrd console=ttyAM0,115200 rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw gpmi badupdater
Using setenv
we can alter the bootargs that are used at startup and cause the Wink Hub to boot into a root shell. We use the following commands to accomplish this:
setenv bootargs 'noinitrd console=ttyAM0,115200 rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw gpmi init=/bin/sh';
And then reboot with:
nand read ${loadaddr} app-kernel 0x00400000 && bootm ${loadaddr}
How did we know init=/bin/sh
needed to be added? Well, the course sort of glosses over that detail but a quick google turns up this:
The init= Argument
The kernel defaults to starting the init program at boot, which then
takes care of setting up the computer for users via launching getty
programs, running rc scripts and the like. The kernel first looks
for /sbin/init, then /etc/init (depreciated), and as a last resort, it
will try to use /bin/sh (possibly on /etc/rc). If for example, your
init program got corrupted and thus stopped you from being able to
boot, you could simply use the boot prompt init=/bin/sh which would
drop you directly into a shell at boot, allowing you to replace the
corrupted program.
So adding init=/bin/sh
to the bootargs allows for booting directly into a shell.
How did we know nand read ${loadaddr} app-kernel 0x00400000 && bootm ${loadaddr}
would reboot?
Well, this is glossed over in the course as well. Looking at the “app_boot” environment variable though we can get some clues. It performs appboot_args
which we can guess probably sets up the boot args that are being modified with /bin/sh. It then proceeds to perform nand read
. What does that do?
According to the Uboot README
nand read addr ofs|partition size
Read size bytes from ofs in NAND flash to addr. Blocks that
are marked bad are skipped. If a page cannot be read because an
uncorrectable data error is found, the command stops with an error.
So this command reads 0x400000 bytes from the “offset/app-kernel” to the “loadaddr” location. This seems to be loading the kernel from the NAND flash into memory. It then proceeds to do bootm ${loadaddr}
.
What does the bootm
command do?
According to this documentation:
“bootm - boot application image from memory”
So the proceeding commands combined load the kernel into memory and then load the kernel. This provides the reboot.
Enjoy Root!
2.2 JTAG接口的调试与漏洞利用
https://blog.csdn.net/qq_33904382/article/details/143067849