5分钟教程:如何通过UART获得root权限
写在前面的话
你知道物联网设备以及其他硬件制造商是如何调试和测试自家设备的吗?没错,绝大多数情况下,他们都会留下一个串行接口,这样就可以利用这个接口并通过shell来读取实时的调试日志或与硬件进行交互。现在主要有两种不同的串行接口,但最常见的一种是通用异步收发器(UART)。
在这篇文章中,我们将讨论如何通过UART来与TP-Link WR841N (v9.0)进行连接,整个实际动手操作时间大约在五分钟左右。
UART
在开始之前,我想先跟大家简单介绍一下UART的工作机制,如果你已经了解了的话,可以直接跳过这个部分。
UART指的是通用异步收发器,跟其他串行接口不同的是,它是一种不依赖于时钟的串行通信接口,它可以适用于单向通信、半双工通信或全双工等场景下,通信本身主要是通过数据包实现的:
寻找UART接口
UART接口在物理设备的电路板上,一般是一个拥有3/4个针脚的面板。在我们的分析场景中(TP-Link WR841N v9.0),端口情况如下图所示:
当你找到UART端口之后,我们还需要区分每一个针脚的功能(GND, VCC, TX, RX)。此时我们需要按照以下步骤进行操作:
1. 识别GND:关掉设备,把你的万用表调到‘连续模式‘,把黑色探针接地(或接其他金属),然后把红色探针依次与上述四个针脚进行接触,如果发出了“哔哔”声,则说明这个针脚为GND。 2. 识别VCC:把万用表调到“DC Voltage(V-)”,把黑色探头接到GND,然后用红色探头去检查UART针脚。然后接点,如果哪个针脚能够出现恒定的高电压(约3.3V或5V),则说明这个针脚就是VCC。 3. 识别TX:在启动过程中的10-15秒时间里,TX针脚会引起非常大的电压波动,因为启动过程中有很多数据需要传输,方法跟寻找VCC针脚的方法相同。 4. 识别RX:RX针脚在整个过程中电压是最低的,相比不用解释太多了。
识别出了所有针脚之后,你就可以焊接一些连接器上去了(Attify Badge):
利用UART与设备交互
在我们真正与UART接口进行通信之前,我们需要先弄清楚波特率(Baud Rate)。所谓波特率,指的是数据在设备之间的传输频率。换句话来说,就是每秒传输几比特的数据。常见的波特率为9600, 38400, 19200, 57600和115200,但是理论上来说,制造商是可以随意设置的。
我们可以使用devttys0的Python脚本来快速寻找到适当的波特率:
$ git clone https://github.com/devttys0/baudrate
$ cd baudrate
下载之后,我们将TP-Link路由器接电,然后在开启设备的同时运行Python脚本:
$ sudo python baudrate.py
之后,你就可以用上下键来扫描不同的波特率了,这个过程其实跟你调整无线电台频率是一样的。
在我们的测试场景下,TP-Link路由器使用的波特率为115200。
为了通过UART来与设备进行交互,我们需要运行下列命令:
screen/dev/ttyUSB0 115200
Boom!!我们成功拿到了shell的root访问权!没错,就是这么简单!接下来,你可以随意查看或修改设备的文件系统了。
意外情况
下面是我在测试过程中所遇到的一些有意思的情况。
TP-Link的安全性确实不容乐观
近期我还对TP-Link WR841N v.9和v.20进行了测试,而我发现当我通过UART尝试访问v.9路由器的shell时,它会要求我输入用户名和密码。但是v.20路由器却直接给我访问设备shell了。
UART+首次启动=启动失败
如果你连接好UART后首次启动设备失败的话,你可以拔掉TX和RX接头,然后再重启设备时重新连接。此时你将会看到Dropbear rsa/dss密钥的创建信息:
后续研究
我现在的主要目标是通过UART在这些路由器中创建后门,创建恶意固件,或修改目标设备上的特定文件。除此之外,我还会分析这两个版本路由器之间的区别。希望本文能够给各位同学的Hacking带来一些思路。
- 实例化和具体化详解
- SparkMllib主题模型案例讲解
- JWT VS Session
- Python文档精要研读系列:hash函数
- scala中常用但其他语言不常见的符号含义 - 心灵空谷幽兰 - 博客园
- 每天一个Linux命令:telnet
- c++基础 explicit
- 每天一个Linux命令:tail
- Hive高级优化
- OpenStack中的RESTful API是如何实现的?
- servlet乱码问题总结
- Servlet学习之web服务器Tomcat 详解
- 结合源码彻底讲解Aggregate vs treeAggregate
- Nginx+uWSGI部署Django网站的详细步骤,脱坑必备,值得收藏!
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- R-wordcloud: 词云图
- 直播APP源码是如何实现音视频同步的
- 动态规划算法练习(5)--medium
- phpstudy漏洞分析原因到修复
- 哈?命令注入外带数据的姿势还可以这么骚?
- 记一次曲折的RCE挖掘
- pytest文档49-命令行参数--tb的使用
- pytest文档50-命令行参数--durations统计用例运行时间
- pytest文档51-内置fixture之cache使用
- pytest文档53-命令行实时输出错误信息(pytest-instafail)
- pytest文档52-命令行参数--setup-show查看fixture的执行过程
- pytest文档54-Hooks函数terminal打印测试结果(pytest_report_teststatus)
- SAS-免费的描述性统计程序自动化创建
- Godot游戏开发实践之四:搬运Unity的Pluggable AI教程
- TypeScript 4.1 新特性:字符串模板类型,Vuex 终于有救了?