[DC29 Quals] Reverse-Tiamat -wp

news2024/11/26 4:33:49

前言:我将尽量以自己做题时的思考过程来组织本文,所以本文可能不适合阅读,知识点也会比较散碎的出现。

​1. qemu-user 简介

简单介绍一点本题所涉及的 qemu 相关知识,需要声明的是这一节不是对 qemu 的源码分析,仅仅包含 qemu-user 执行过程的一个概括,省略了大量 qemu 的细节,甚至很多地方为了方便理解本题表述并不准确。

图中黄底为比较重要的函数,整体的执行流程大概是:从 main 函数出发,执行一些初始化操作之后进入 cpu_loop 函数,cpu_loop 函数循环调用 cpu_exec 。cpu_exec 也包含一个循环,负责一条一条(并不准确)反汇编 guest 程序的指令、生成能够在 host 主机执行的代码,并执行所生成的代码。当 cpu_exec 遇到中断时,会返回到 cpu_loop 交由 cpu_loop 进行处理。

在 cpu_exec 函数内部更详细的调用过程如图所示,需要注意的有 3 个函数:

gen_intermedia_code:负责反汇编 guest instruction,生成中间代码(TCG operations),通常被称作前端。

tcg_gen_code:负责把中间代码转换为在 host 机器上执行的代码,通常被称作后端。

tcg_qemu_tb_exec:负责调用执行由 tcg_gen_code 生成的 host 代码。这里是调试的关键点,在这里下断点就可以知道 guest 指令被翻译成了什么样的 host 指令。

举个例子对于 mips 指令 sw $zero, 8($sp) 其得到的 host 指令可能是这个样子的:

CPUArchState 类型就是 qemu 模拟的 target cpu 架构。[0] 处的代码是主要生效的代码,其将 0 写入 29 号寄存器指向的地址 + 8 的位置(在 mips 中 29 号寄存器就是 $sp)。

2. 题目初分析

题目总共给了七个文件,首先查看 Dockerfile ,除了把现有的文件复制过去之外还新增了几个文件:

/flag:flag

/lic:flag 的 md5

/1.mz-f.mz:同样的内容 STRANGE GAME\nTHE ONLY WINNING MOVE IS\nNOT TO PLAY.\n

其他文件大致的意思就是执行 /qemooo /liccheck.bin ,于是理所应当将 liccheck.bin 丢进 IDA,但是出了一点问题。 

IDA 只能反汇编几条指令,结合 qemooo 这个文件名字可以猜到作者魔改了 qemu。好在 qemooo 是带符号的,这个时候可以在 Functions 窗口看到一些奇怪的单词:aarch64、riscv。难道说那些指令不是 mips 指令?有了上一节的扫盲,现在我们知道或许应该去 tb_gen_code() 里面看看 qemooo 是怎么反汇编这些指令的。

芜湖,我们好像发现了关键。不过这个看起来可不太妙,四种架构 X 大小端切换,让我想起了上个月做的我师傅 yype 的 gatesXgame 。简单通过交叉引用确定了 tmap_arch 数组没有在其他地方被修改之后,将数组 dump 下来开始写一个简单的反汇编程序。

这里有个小地方可能需要注意下:capstone 得切换到 next 分支才能反汇编 riscv。

3. 人类可读代码计划 

Emmm,虽然确实成功了但是我不确实太认为这个能够帮助我们理解程序逻辑。至少我们可以给所有寄存器换一下名,或许 r0-r32 是更好的表示。这里需要去查找各种架构的寄存器对应关系,手册、capstone 源码都会有帮助。 

我觉得好些了,但我突然觉得还想更好一些,所以稍微修改了反汇编器输出类似高级语言的代码。(事实上我最开始想生成 C 代码丢给 IDA 帮忙分析,但是后面踩坑太多就放弃了 XD)

看起来可以大干一场了,但是初始化之后的第一条指令就有点奇怪,r15 寄存器是个啥?我一调试发现这条指令生成的 host 代码甚至没有访问 r15 寄存器,我一回头看最开始的汇编,发现这里是对 pc 寄存器的操作,所以我这里有个未验证的猜测,前端 gen_intermedia_code(或许是)在反汇编生成 TCG 的时候,可能会对一些特殊寄存器有特殊的操作,例如 pc 寄存器会被硬编码为当前 pc 的数值常量。

知道这个后继续往下走,调试没几步寄存器的变化又和预想的不一样了,测试了一下发现是 sparc 这一类指令的问题,所以我回到 cpu_tb_exec()来确认寄存器映射的情况,发现 sparc 类指令的寄存器映射和手册上的不一致,例如对于指令 add     %g1, 0xd00, %i7 生成的 host 代码如下所示。按照手册上的说法 g1 对应 r1,但是这里却取了 r2 和 r3 的数值(_QWORD);i7 应该对应 r31,却存到了一个不属于通用寄存器的内存,并且也是 64 位的操作。 

对 sparc 类指令的寄存器对应关系进行进一步分析之后可以发现行为大致是这样:

首先对 sparc 类寄存器的操作不同于其他架构,它是 64 位的。

对于 o0-o7、l0-l7、i0-i7,其被映射到了不属于通用寄存器内存的一块地方(regwptr),可以把它看作是扩展 cpu 的扩展寄存器,在本文中用 eR0-eR46 表示,为了一致性(其实没必要)把它们都定义是 32 位寄存器,所以相当于 o0 映射到了 eR0、eR1 两个 32 位寄存器。

对于 g0-g7,他们被映射到了 r0-r15,相当于 g0 映射到了 r0、r1 两个寄存器。

这里按理要修改一下反汇编器生成类似 (rx, rx) = (rx, rx) op (rx, rx) 类型的代码,但是我粗略看了一下,sparc 指令执行后高位的寄存器都是没有被使用的,所以我做题的时候偷了个懒只是把这个点记在脑子里,然后还是把 g0 映射到了 r0,给后面留下了一个隐患。

几乎是最后,我们还需要为系统调用确定调用约定。本题中四种架构都有涉及系统调用的指令,前面提到过,在遇到中断的时候 qemu 会返回到 cpu_loop() 进行处理,在 cpu_loop() 中可以找到类似下面的调用: 

找到所有的调用然后还原出所有的调用约定: 

确定系统调用所对应的具体操作,还需要知道 syscall table。对于 syscall number,在 linux/Documentation/ABI/stable/syscalls 有写道:Note that this interface is different for every architecture that Linux supports. Please see the architecture-specific documentation for details on the syscall numbers that are to be mapped to each syscall.

所以对于不同的架构,我们需要在 qemu/linux-user/ 目录下面去寻找对应架构的 syscall table,用于确定系统调用所对应的具体操作,以便下一步程序执行逻辑的还原。这一步相当枯燥,且相当容易出错!

要生成一份准确的代码对我来说并非易事,除了上面提到的,还有一些细节需要注意,例如:

sparc 的 dest 寄存器在最后一个操作数,而其他架构是第一个操作数。

branch 类指令目标地址的确定,例如 riscv 的 j 指令和 mips 的 b 指令有所区别,b 是当前地址加上偏移,j 是当前地址减 4 加上偏移。

call 类指令的特殊处理,作者为了恶心人用了两种方法来调用函数:jal 指令、手动存入返回地址到寄存器然后 jmp。retrun 指令也有两种表示:ret 指令,手动将寄存器赋值给 pc。最恶心的是有一个语义应该是 goto 的指令是用 call 来实现的。

4. 程序逻辑分析 

有了上面的工作,我们可以比较轻松的着手分析程序的逻辑,不过这依旧是一个需要耐心的工作,特别是在我没有 IDA 帮助的情况下。我考虑过要不要给出分析过程,不过那样可能文章就太长了,在这里我只给出分析的结果。

程序是一个菜单题,初始化的时候主要会调用一个获得随机数的函数(见下面 'n' 对应的操作),之后就进入菜单选项。还原出来的选项和对应的操作如下:

e:输入 input,并对 input 进行校验,要求值其在 ['0'-'f']。

v:要求在输入 input 后调用。读入 license,用随机数对其进行异或加密,然后与 input 比较,若相同则输出 flag。(限制执行次数 0x8 )

n:从 /dev/random 读入四字节用于更新随机数,如果此时已经读入了 license,就用其对 license 进行异或加密。(限制执行次数 0x18)

p:打印 input。

joshua:打印一点没用的东西。

l:对解题没有帮助的一个无聊的函数 XD。

r:NOP。

在这一步确定全局变量寄存器以及内存数据的分布也很重要。

4. 找到 BUG(s)

BUG1: r0 misuse 

’p‘ 操作对应的操作很短,实际有意义就三行,第一行将 input 的地址赋值给 r10 寄存器,第二行将 r0+0x20 赋值给 r11 寄存器,在 print_sth 函数中,r11 用来控制泄露的长度。通过上一节的分析可以知道加密后的 license 就存放在 input 后面,所以 r0 寄存器很可能可以控制然后用来泄露。

注意在 riscv 和 mips 中 r0 是 zero 寄存器,它和 pc 一样属于比较特殊的寄存器,(应该)会被直接翻译为常量 0,在程序中有很多 + zero 的无用操作来迷惑你。不过好在之前看到 pc 寄存器的时候就对 r0 寄存器留了一个心眼,我迅速定位了所有使用真 r0 寄存器的指令(所以我的反汇编代码里为什么不早点对 zero 特殊处理 XD),发现除了这条指令确实使用 r0 寄存器外,还有一个地方存在对 r0 寄存器的赋值。 

赋值发生在 'n' 操作对应的 get_random 里,open 作为 svc 系统调用,返回值存到了 r0 寄存器里,后续返回到 menu_loop 之前也没有对 r0 寄存器的再赋值,意味着我们可以在 'n' 操作后马上调用 'p' 操作进行泄露。所以我们第一个 payload 就是 "e"+"1"*0x20+"vnp" !

BUG2: syscall number misuse

芜湖,看起来我们已经摸到 flag 了!但是,等一下,为什么泄露了五个字节,fd 不是应该为 3 才对吗?再回头审计代码发现 'v' 操作里面读取 license 的时候,open 后没有 close,这确实会让 fd 加 1,但是只执行一次 ’v‘ 操作为什么 fd 会加 2?这里可以调试跟踪所有 open 和 close 系统调用的执行情况,最后会发现在 'n' 操作里,看似是 close 的操作其实根本没有执行 do_syscall,因为它传递了另一个架构的系统调用号!这里感受到了作者的恶意,在还原系统调用的时候真的很枯燥,看到 open、read 自然就觉得之后应该是 write。

事实上我在做题的时候没有发现这个漏洞,因为我还犯了另一个错误,我忘记在根目录创建 lic 文件,导致 'v' 操作的 open 不会成功,从而导致之后只能泄露出四个字节。

现在我们有两个可以让 fd 增加的函数,并且我们可以调用他们共计 0x20 次,加上 stdio 给我们贡献了 3 个文件描述符,足以让我们泄露所有的 license。是时候构建我们的第二个 payload: "e"+"1"*32+"v"*7+"n"*0x16+"p" 

5. 还原 license

我们泄露的不是 license,是 license 与一个四字节随机数循环异或后的数值,不过这足以给我们很多信息了:异或是四字节进行的,意味着对于随机数的每一个字节,license 中都有 8 个字节都使用它来异或加密。而 license 每个字节取值区间为 [‘0‘-’f'],所以对于泄露的每个字节,可以确定一个长度为 16 的集合,包含了所有随机数字节可能的取值。而对于使用同一个随机数字节来加密的 8 个字节,这 8 个随机数字节集合得取个交集。这听起来可以把可能的 license 缩小到一个可以接受的范围,马上写一个脚本跑一下: 

OMG,难以相信真正的 license 就在这 8 字符串当中!我甚至可以接受手工测试的开销,我已经等不及了,我早就已经想好了怎么进行测试。

事实上我不确定这是否是预期解,因为对于其他的 flag,很可能候选的 license 数量在 3 位数以上,虽然暴力也花不了多少时间,但是总觉得有点奇怪。不过我确实知道有两个做出这道题的队伍也使用了这种解法。

6. 错误的道路

似乎我们只需要先输入 ex...xvnp 就可以泄露 License ^ Rand0 ^ Rand1 的数值,然后输入 np 就可以泄露 License ^ Rand0 ^ Rand1 ^ Rand2 的数值,两个泄露的数值异或就可以得到 Rand2 的数值。 Rand2 是最新的随机数,校验函数将用它来异或 License 然后与我们的输入做比较,那我们使用 Rand2 来异或我们可能的 Licese,将其输入然后调用验证函数,如果是正确的 License 就可以通过校验输出 flag 了?

我激动地写完脚本,然后发现所有的 License 全部校验失败。在确定正确的 License 一定在之中后,我突然意识到,输入的时候要求所有字符都是在 '0'-'f'!怎么可能?这意味着输入一定是正确的 License,但是与输入比较的数据是与随机数异或之后的 License。难道说有办法让读入的 License 不被随机数异或?

7. 最后的 Flag

这个时候马上就想起来了,随机数是存在 r15 寄存器里的,虽然之前检查过所有对 r15 寄存器赋值的语句,但是遗漏了一点,sparc 的指令在对 r14 寄存器赋值的时候会把 r15 清零!所以我立马搜索所有对 r14 赋值的语句,最后在 joshua 操作里找到了它。 

虽然 r14 被伪装成了一个传参的临时变量,但在这个没用的函数里面它就是显得那么的突兀。

所以,我们只需要很简单地在校验之前调用一次这个函数: ed64be88c7427f0255c5002f81a9350fbjoshua\nv

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1173454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软件测试】Linux系统下搭建JDK+JMeter环境详细步骤,一篇概全...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 Linux搭建JDK环境…

王道p18 07.将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表。(c语言代码实现)

视频讲解在这:👇 p18 第7题 c语言代码实现王道数据结构课后代码题_哔哩哔哩_bilibili 本题代码如下 int merge(struct sqlist* A, struct sqlist* B, struct sqlist* C) {if (A->length B->length > C->length)//大于顺序表的最大长度r…

NewStarCTF 2023 公开赛道 Web

NewStarCTF 2023 公开赛道 Web WEEK1|WEB 泄漏的秘密 泄露的秘密,直接看常见的目录robots.txt,www.zip直接那道两段flag 也可以用dirsearch工具扫描,但是BUUOJ平台的网站只能开底线程,不然全是429 PART ONE: flag{r0bots_1s_s0_us3ful $…

宝塔面板使用Supervisor进程守护插件,配置守护Mysql的操作教程。

本篇文章主要讲解,在宝塔面板中使用Supervisor进程守护插件,配置守护Mysql的操作教程。 作者:任聪聪 日期:2023年11月5日 一、安装守护进程插件 安装插件一、进程守护插件 安装说明:在软件商店中搜索“进程守护”&am…

Leetcode-1 两数之和

暴力穷举 class Solution {public int[] twoSum(int[] nums, int target) {int[] num new int[2];for(int i0;i<nums.length-1;i){for(int ji1;j<nums.length;j){if(nums[i]nums[j]target){num[0]i;num[1]j;}}}return num;} }HashMap&#xff0c;记录下标和对应值&…

【漏洞复现】weblogic-10.3.6-‘wls-wsat‘-XMLDecoder反序列化(CVE-2017-10271)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞扫描nacsweblogicScanner3、漏洞验证 说明内容漏洞编号CVE-2017-10271漏洞名称Weblogic < 10.3.…

Qt::WindowFlags

Qt::WindowFlags 文章目录 Qt::WindowFlags摘要窗口&部件Qt::WindowFlags&WindowType窗口类型窗口提示 关键字&#xff1a; Qt、 Qt::WindowFlags、 Qt::WindowType、 关键字4、 关键字5 摘要 今天在公司解决自己的Bugs的时候&#xff0c;发现一个以前可以用的功…

MSF暴力破解SID和检测Oracle漏洞

暴力破解SID 当我们发现 Oracle 数据库的 1521 端口时,我们可能考虑使用爆破 SID(System Identifier)来进行进一步的探测和认证。在 Oracle 中,SID 是一个数据库的唯一标识符。当用户希望远程连接 Oracle 数据库时,需要了解以下几个要素:SID、用户名、密码以及服务器的 I…

antv/g6之交互模式mode

什么是mode 在 AntV G6 中&#xff0c;“mode” 是用于配置图表交互模式的一种属性。通过设置 “mode”&#xff0c;可以控制图表的行为&#xff0c;以满足不同的交互需求。可能在不同的场景需要展现的交互行为不一样。比如查看模式下点击一个点就选中的状态&#xff0c;在编辑…

ZZ038 物联网应用与服务赛题第J套

2023年全国职业院校技能大赛 中职组 物联网应用与服务 任 务 书 &#xff08;J卷&#xff09; 赛位号&#xff1a;______________ 竞赛须知 一、注意事项 1.检查硬件设备、电脑设备是否正常。检查竞赛所需的各项设备、软件和竞赛材料等&#xff1b; 2.竞赛任务中所使用…

LeetCode 热题100——链表专题

一、俩数相加 2.俩数相加&#xff08;题目链接&#xff09; 思路&#xff1a;这题题目首先要看懂&#xff0c;以示例1为例 即 342465807&#xff0c;而产生的新链表为7->0->8. 可以看成简单的从左向右&#xff0c;低位到高位的加法运算&#xff0c;4610&#xff0c;逢…

1115 Counting Nodes in a Binary Search Tree(30分)

题目翻译&#xff1a; 给定一组序列&#xff0c;请建立二叉搜索树 题解思路&#xff1a; 注意是二叉搜索树BST&#xff0c;而非平衡二叉树AVL&#xff0c;两者的区别如下&#xff1a; BST&#xff1a; AVL&#xff1a; 因此只需要采用常规的建树手段即可&#xff0c;需要注…

【ARMv8 SIMD和浮点指令编程】浮点加减乘除指令——四则运算

浮点指令有专门的加减乘除四则运算指令,比如 FADD、FSUB、FMUL、FDIV 等。 1 FADD (scalar) 浮点加法(标量)。该指令将两个源 SIMD&FP 寄存器的浮点值相加,并将结果写入目标 SIMD&FP 寄存器。 该指令可以产生浮点异常。根据 FPCR 中的设置,异常会导致在 FPSR 中…

如何避免 JavaScript 中的内存泄漏?

一、什么是内存泄漏&#xff1f; JavaScript 就是所谓的垃圾回收语言之一&#xff0c;垃圾回收语言通过定期检查哪些先前分配的内存仍然可以从应用程序的其他部分“访问”来帮助开发人员管理内存。垃圾回收语言中泄漏的主要原因是不需要的引用。如果你的 JavaScript 应用程序经…

【Spring源码分析】BeanFactory系列接口解读

认识Bean工厂 一、认识Bean工厂BeanFactoryListableBeanFactoryHierarchicalBeanFactoryAutowireCapableBeanFactoryConfigurableBeanFactoryConfigurableListableBeanFactory 二、总结 一、认识Bean工厂 Spring Bean 工厂是Spring框架提供的一种机制&#xff0c;用于创建和管理…

艺术的维度:洞察AI诈骗,优雅防范之艺术

当前&#xff0c;AI技术的广泛应用为社会公众提供了个性化智能化的信息服务&#xff0c;也给网络诈骗带来可乘之机&#xff0c;如不法分子通过面部替换语音合成等方式制作虚假图像、音频、视频仿冒他人身份实施诈骗、侵害消费者合法权益。 以下是一些常见的AI诈骗例子&#xf…

SurfaceFlinger的硬件Vsync深入分析-千里马android framework车机手机系统开发

背景&#xff1a; 学过或者你看过surfaceflinger相关文章同学都知道&#xff0c;vsync其实都是由surfaceflinger软件层面进行模拟的&#xff0c;但是软件模拟有可能会有误差或偏差&#xff0c;这个时候就需要有个硬件vsync帮忙校准。 故才会在surfaceflinger的systrace出现如下…

MFC串口通信(SerialPort)

目录 1、SerialPort类的介绍和使用&#xff1a; &#xff08;1&#xff09;、SerialPort类的功能介绍 &#xff08;2&#xff09;、SerialPort类提供接口函数的介绍 1&#xff09;、InitPort函数 2&#xff09;、控制串口监视线程函数 3&#xff09;、获取事件&#xff0c…

一文读懂从 CPU 多级缓存 缓存一致性协议(MESI)到 Java 内存模型

文章目录 CPU 多级缓存 & 缓存一致性协议&#xff08;MESI&#xff09;CPU 多级缓存缓存一致性协议&#xff08;MESI&#xff09;缓存行&#xff08;Cache line&#xff09;四种缓存状态缓存行状态转换多核协同示例网站体验 MESI优化和引入的问题Store Bufferes & Inva…

笔记软件 Keep It mac v2.3.3中文版新增功能

Keep It mac是一款专为 Mac、iPad 和 iPhone 设计的笔记和信息管理应用程序。它允许用户在一个地方组织和管理他们的笔记、网络链接、PDF、图像和其他类型的内容。Keep It 还具有标记、搜索、突出显示、编辑和跨设备同步功能。 Keep It for mac更新日志 修复了更改注释或富文本…