2022数字中国车联网安全CTF writeup - uds_server
介绍
这是一道uds诊断协议的逆向题。比赛的时候时间太短没做出来,又花时间研究了一下拿出来分享。
题目
uds_server程序逻辑
- main
- 启动后监听13400端口
- 接收client请求
- 启动Server
- Server初始化后进入loop
- 接收处理客户端发送的请求
- 其中handleRoutingActivationMessage函数负责注册
- 注册后可以调用提供的service
- jmp rax跳转到不同的服务
- 所提供的服务如下
服务列表
服务号 |
服务名称 |
0x10 |
UdsSessionControlService |
0x27 |
UdsSecurityAccessService |
0x31 |
UdsRoutineControlService |
0x36 |
UdsTransferDataService |
0x37 |
UdsRequestTransferExitService |
0x38 |
UdsRequestFileTransferService |
0x3d |
UdsWriteMemoryByAddressService |
两个目标分析
- UdsRequestFileTransferService
构造满足的条件后,我们传送的路径字符串会拼接到/tmp/data/后面。同时过滤../。
- UdsRoutineControlService
这个函数从getflag这看起来就像目标函数,要求的条件很多。
唯一一个不可控因素backdoorMem是random出来的。
可以通过UdsWriteMemoryByAddressService写内存。
攻击思路
1、注册,使客户端能访问uds服务
- sourceAddress=0x1
- targetAddress=0x100
2、构造满足UdsRoutineControlService的条件
- securityLevel=1
- currentSession=2
- retineControlType=1
- routineIdentifier=0xbac4
- backdoorMem地址中内容为0xdeadbeef
3、backdoorMem取值范围0x123000-0xfffff000后三位固定为0。
4、通过UdsWriteMemoryByAddressService向0x125000写入内存deadbeef
5、n随机区间[0~1048284] 多进程循环调用直到 n==2 backdoormem=0x125000
6、调用UdsRoutineControlService
构造请求
doip协议
doip协议 |
protocolVersion |
inverseProtocolVersion |
dataType |
length |
userdata |
1字节 |
1字节 |
2字节 |
4字节 |
任意长度 |
0x02 |
0xfd |
0x5 0x8 0x8001 |
4字节 |
任意长度 |
构造注册请求
注册协议 |
1字节 |
1字节 |
type 2字节 |
length 4字节 |
ActivationType 1字节 |
sourceAddres 2字节 |
8字节 |
0x02 |
0xfd |
0x5 |
0x00 0x00 0x00 0x0b |
0x00 |
0x01 0x00 |
0x00*8 |
设置currentSession
- 调用UdsSessionControlService
- 需要先将currentSession设置成3 保证下次设置2的时候可以走else分支
session协议 |
1字节 |
1字节 |
type 2字节 |
length 4字节 |
srcaddr 2字节 |
dstaddr 2字节 |
服务号 1字节 |
sessionid 1字节 |
0x02 |
0xfd |
0x8001 |
0x00 0x00 0x00 0x06 |
0x00 0x01 |
0x01 0x00 |
0x10 |
0x03 |
0x02 |
0xfd |
0x8001 |
0x00 0x00 0x00 0x06 |
0x00 0x01 |
0x01 0x00 |
0x10 |
0x02 |
设置securityLevel
- 调用UdsSecurityAccessService
- 请求seed
- 根据seed计算key
- seed进行变换后调用xteaEncryptGetKey进行加密计算key
- 相等的话设置securityLevel=1
security协议 |
1字节 |
1字节 |
type 2字节 |
length 4字节 |
srcaddr 2字节 |
dstaddr 2字节 |
服务号 1字节 |
accessType 1字节 |
Key 4字节 |
0x02 |
0xfd |
0x8001 |
0x00 0x00 0x00 0x06 |
0x00 0x01 |
0x01 0x00 |
0x27 |
0x01 |
|
0x02 |
0xfd |
0x8001 |
0x00 0x00 0x00 0x0A |
0x00 0x01 |
0x01 0x00 |
0x10 |
0x02 |
根据seed计算的key |
写入0xdeadbeef到backdoorMem
- 调用UdsWriteMemoryByAddressService
- 设置memoryAddress为0x2000 0x123000+0x2000=0x125000
- 设置写入的内容为0xdeadbeef
- 判断是否有返回,有返回则写入成功
writememory协议 |
1字节 |
1字节 |
type 2字节 |
length 4字节 |
srcaddr 2字节 |
dstaddr 2字节 |
服务号 1字节 |
memSizeLen&memAddrLen 1字节 |
address |
写入内容长度 1字节 |
写入内容 |
0x02 |
0xfd |
0x8001 |
0x00 0x00 0x00 0x0F |
0x00 0x01 |
0x01 0x00 |
0x3d |
0x14 |
0x00 0x00 0x20 0x00 |
0x04 |
0xef 0xbe 0xad 0xde |
调用getflag函数
- 调用UdsRoutineControlService
getflag协议 |
1字节 |
1字节 |
type 2字节 |
length 4字节 |
srcaddr 2字节 |
dstaddr 2字节 |
服务号 1字节 |
controlType 1字节 |
Identifier 2字节 |
0x02 |
0xfd |
0x8001 |
0x00 0x00 0x00 0x08 |
0x00 0x01 |
0x01 0x00 |
0x31 |
0x01 |
0xba 0xc4 |
bash脚本
1
2
3
4
5
|
for
((i
=
1
;i<
1000000
;i
+
+
));
do
.
/
uds;
done
|
启动多个该脚本同时进行。增加并发减小爆破时间。
patch 测试 exp
真正的exp
正常情况下这样爆破是没问题的,但我一直在想这是CTF没有那么多时间让你爆破,肯定还有其他办法。得知....//....//可以路径穿越后。
又有了攻击思路:
- 和前面一样。
- 这里不直接读内存,通过UdsRequestFileTransferService设置路径
读取路径为....//....//proc/self/maps
经过过滤拼接后得到/tmp/data/../../proc/self/maps
- 设置路径包构造
设置读取文件协议 |
1字节 |
1字节 |
type 2字节 |
length 4字节 |
srcaddr 2字节 |
dstaddr 2字节 |
服务号 1字节 |
modeOfOperation 1字节 |
filePathAndNameLength 2字节 |
filePath |
compressionMethod encryptingMethod 1字节 |
0x02 |
0xfd |
0x8001 |
0x00 0x00 0x00 0x23 |
0x00 0x01 |
0x01 0x00 |
0x38 |
0x04 |
0x00 0x1a |
....//....//proc/self/maps |
随便1字节 |
- 调用UdsTransferDataService读取文件
读取文件协议 |
1字节 |
1字节 |
type 2字节 |
length 4字节 |
srcaddr 2字节 |
dstaddr 2字节 |
服务号 1字节 |
blockSequenceCounter 1字节 |
0x02 |
0xfd |
0x8001 |
0x00 0x00 0x00 0x06 |
0x00 0x01 |
0x01 0x00 |
0x36 |
0x01 |
- 对返回的/proc/self/maps进行解析获取到backdoorMem基址。基址减去0x123000获取到偏移
- 将0xdeadbeef写入backdoorMem基址
调用getflag
成功获取flag
更多【2022数字中国车联网安全CTF writeup - uds_server】相关视频教程:www.yxfzedu.com