0x00 简介
Qiling框架是基于unicorn的多架构平台模拟执行框架,本质上是在沙箱环境内模拟执行二进制文件,在模拟执行的基础上提供统一的分析API,这个API包括插桩分析、快照、系统调用和API劫持等。
QilingLab是受FridaLab的启发,由11个小挑战组成的二进制程序,用来帮助新手快速熟悉和掌握 Qiling 框架的基本用法。
QilingLab 下载地址:https://www.shielder.com/attachments/qilinglab-aarch64
QilingLab rootfs 下载地址:https://github.com/qilingframework/rootfs/tree/master/arm64_linux
Qiling文档:https://docs.qiling.io/en/latest/
实验环境以及exp都打包在github里了:https://github.com/Ryze-T/qilinglab-slove
挑战如下:
0x01 挑战
exp模板如下:
1 |
|
1. Challenge1
Challenge1: 在0x1337地址处写入1337
操作内存:https://docs.qiling.io/en/latest/memory/
根据文档,写入内存之前需要先调用 mem.map 映射内存区域,再调用 mem.write 写入,因此exp如下:
1 |
|
2. Challenge2
Challenge2: 使系统调用uname返回正确的值
先判断正确的值是什么:
需要 utsname.sysname = QilingOS,utsname.version = ChallengeStart。
utsname结构体如下:
通过 os.set_syscall 加上 QL_INTERCEPT.EXIT 参数,在调用结束后劫持 uname 的返回值,替换成验证的字符串,参考文档:https://docs.qiling.io/en/latest/hijack/。
1 |
|
3. Challenge3
Challenge3: /dev/urandom 和 getrandom 相等
程序需要使/dev/urandom 和 getrandom 相等,且一个字节的随机数和其他的随机数都不一样。
对 getrandom的劫持与Challenge2一样;对 /dev/urandom的劫持要用到 add_fs_mapper,add_fs_mapper可以实现将模拟环境中的路径劫持到主机上的路径或将读/写操作重定向到用户定义的对象。参考文档:https://docs.qiling.io/en/latest/hijack。
1 |
|
4. Challenge4
Challenge4: 进入禁止的循环
IDA F5识别流程有问题,查看汇编:
通过汇编可以看到,程序进入死循环,关键点在于控制判断结果。这里用到 hook_address 这个API,可以hook特定地址。注册的回调将在执行指定地址时被调用。参考文档:https://docs.qiling.io/en/latest/hook/。
通过 https://github.com/qilingframework/qiling/blob/dev/qiling/profiles/linux.ql 可知 qiling 默认配置 linux64 加载基地址为 0x555555554000,cmp那条指令偏移是 0xFE0,hook_address 将 x0 改成比 x1 小即可。
1 |
|
5. Challenge5
Challenge5: 预测每次对rand的调用
只要让每次 rand() 返回值等于0就可以。通过 ql.os.set_api() 就可以实现:
1 |
|
但是没有显示 solved。。。
6. Challenge6
Challenge6: 避免无限循环
和 Challenge4 一样,看汇编:
使 cmp 前使 x0=0,就可以跳出循环。
1 |
|
challenge5 出现 solved 了,但是整个程序报错了。。。
7. Challenge7
Challenge7: 不要浪费时间等待 sleep
劫持 sleep 函数,把 x0 改成 0 即可:
1 |
|
一切恢复正常:
Challenge5 无回显应该是因为 Challenge6 存在死循环,Challenge6 接触死循环后 Challenge5 就正常了,但是由于修改了参数,导致 Challenge6 因为参数报错,劫持后修改参数,全部就正常了。
8. Challenge8
Challenge8: 在目标地址写入结构体
看代码,应该是结构体里套结构体,
结构应该如下:
1 |
|
这里需要通过固定的 0x3DFCD6EA539 去找到结构体位置,进而修改 flag。qiling 提供了ql.mem.search用来搜索内存,但是实际搜索的时候发现会找到不止一个内存地址,且返回为 list:
因此还需要利用 Random data 进行比较。
参考文档:https://docs.qiling.io/en/latest/memory/
1 |
|
9. Challenge9
Challenge9: 修改字符串操作
只要修改strcmp(src,dest) == 0 的结果就行,通过 os.set_api 劫持 strcmp即可:
1 |
|
10. Challenge10
Challenge10: 伪造成’cmdline’ 文件来返回正确的内容
逻辑很简单,伪造 /proc/self/cmdline 这个文件,内容为”qilinglab” 即可。可以通过 os.set_api 劫持 strcmp,也可以通过 add_fs_mapper 映射到自定义实现或主机路径:
1 |
|
11. Challenge11
Challenge11: Bypass CPUID/MIDR_EL1
逻辑很简单,判断 x1 是否等于 x0,hook_address修改一下:
1 |
|
0x02 EXP
1 |
|