写在前面的话
在这篇文章中, 我们将对闪存进行分析. 我的实验目标是一台别人 "捐赠" 过来的 Netcomm N300 路由器, 在进行了深入研究之后, 我可以通过修改设备闪存的读入操作并从未认证的 web 接口获取目标 Web 服务器的内存数据.
开始分析
我们的路由器使用的是一块 Macronix MX15L12835FMI 闪存芯片(16 针脚 SOP):
首先, 我需要观察芯片的常规操作. 在研究过程中, 我发现它的闪存并没有得到充分使用, 只有设备在启动 (或加载整个操作系统) 时或在使用 Web 管理面板时会使用到闪存. 闪存芯片似乎使用的是 Single API 模式, 其常规读取命令如下所示:
命令开头为一个 05 FF 命令, 根据数据表提供的信息, 这条命令可以读取出寄存器的状态信息. 我最初的目的是对闪存读取命令进行篡改, 并用它来从硬盘中读取数据.
考虑到 SPI 命令是与时钟信号同步的, 那我的攻击同样可以跟同一个时钟信号同步: 我可以记录下时钟上升沿信号的数量, 并在特定数量的时钟信号下将闪存芯片的 15 号针脚接地, 然后修改闪存的读取命令并用它来读取其他信息. 放大时钟信号后我们可以看到, 数据只会在时钟信号的下降沿发生变化, 所以我们的攻击应该是有效的.
首先我们进入到设备的串行控制台中, 然后使用命令 cat /dev/mtdblock0 来触发闪存的读取命令. 该命令的原始状态如下所示:
为了方便进行对比, 所以我运行了 cat /dev/mtdblock2:
接下来, 我连接了一个晶体管和一个 FPGA,FPGA 可以读取时钟信号并控制晶体管的开关, 接地针脚 15 暂时等待几个时钟周期, 并让其中的一个读取指令地址失效:
我还专门编写了一个脚本来让程序等待一定的时钟周期, 并修改闪存的读取操作, 然后运行 cat /dev/mtdblock2 并通过示波器来监控闪存的命令执行情况:
如果你仔细看的话, 你就会发现右边是原始闪存读取操作的残余部分(原始命令 / dev/mtdblock2 为 03 01 00 00), 我们可以通过运行 cat /dev/mtdblock2 命令来验证我们的发现:
需要注意的是, 命令确实成功执行了,/dev/mtdblock2 的第一个数据块跟之前 / dev/mtdblock0 的一样, 表示我们的操作已经成功了.
现在, 我们就可以用这种方法来对 Web 服务器接口进行攻击了, 如果我可以让硬盘中的某个资源加载失败, 理论上来说我就可以让它来读取任何我想要读取的内容了, 比如说通过 Web 请求来获取到固件文件等等.
但是, 我很快就遇到了如下所示的问题:
虽然我可以从物理闪存中读取任意区块, 但我无法保证数据可以正确解压. 虽然 Web 服务器似乎还可以正常工作, 但是其中的一个图片已经无法正确加载了. 用 Burp 进行分析后, 我很快就找到了 "罪魁祸首":
这是一个针对 / wireless_1.gif 的有效请求的一条响应数据, 我知道这是一个无效的 GIF 文件, 但我并不知道它到底是什么, 我猜测它要么来自于 Web 服务器的内存, 或者是磁盘中的数据块.
为了进行测试, 我对整个 Web 应用程序进行了分析, 然后发送了一条新的 / wireless_1.gif 请求:
神奇的是, 这个 gif 文件竟然自己发生了变化, 而且我也没观察到其他的 SPI 流量生成, 这表示我成功实现了内存泄漏(很可能是一个内存用后释放漏洞), 只不过唯一的遗憾是它并非目标系统的密码文件.
攻击代码
PoC:[ 点我获取 https://gist.github.com/CreateRemoteThread/b39b208deba8777e46b18c4a92d20bd8 ]
总结
虽然这项攻击技术对物联网设备来说可能没那么有效, 但是它的影响还是显而易见的, 因为我们可以在不需要系统级访问控制权限的情况下, 就能够随意加载出闪存中存储的数据了.
来源: http://www.tuicool.com/articles/UNJBn2e