CISCN2023初赛之Re WP
去年出了两道,已经没多少印像了,题在nssctf可以拿到
BabyRe
给了一个xml文件,用浏览器打开可以直接看到源代码,之前一直只知道xml是用来传输数据的不知道具体是怎么使用和打开
百度后知道,xml类似html,和js,是一种可以自己创建元素标识的可扩展标记语言,而html他们是预标记,元素类型文字都是已经定义好的,所以照我的理解,每个xml文件都应该是有它的特定的编码和解析的脚本,不存在说通用的软件或者程序可以直接运行它,可以使用java调用dom库对xml中元素提取并且处理,实际上看作文件读取的实例化的数据结构或者其他
打开后,找了半天发现开始有一串链接,可以推测出这个文件是该网站的脚本文件(事实上没做过的话很难推测出,多试试总会撞出来的😑)
脚本分析
在网站找到导入后导入文件,发现这是一个少儿编程的类似模块组建的网站,有点像国内的编程猫等软件
- 可以发现他是对输入从下标1开始对(i,i-1)进行异或然后对结果与scret比对
- 根据左边插入的顺序可以手动整理出[102,10,13,6,28,74,1,3,7,4,85,0,4,75,20,92,92,8,28,25,81,83,7,28,76,88,9,0,29,73,0,86,87,82,84,85,4,85,87,30]
wp
1 | flag =[102,10,13,6,28,74,3,1,3,7,85,0,4,75,20,92,92,8,28,25,81,83,7,28,76,88,9,0,29,73,0,86,4,87,87,82,84,85,4,85,87,30] |
ezByte
分析
这道题当时看的时候完全没有头绪,找不到入口点,后面看师傅们的题解才知道自己对调试这一块的东西了解的太少了
dwarf
程序的编写通常除了编译外我们还需要不断修改,如果只是静态的看很多bug很难找出来,于是又有了调试器,但调试器又该怎么工作呢,最开始是利用CFA相关伪代码,但之后发现远远不够具体,也并不能恢复所有的寄存器,于是又有了dwarf,此时rbp也可以独立出来不必继续承担保留栈底地址了,一般情况下被保留在.en_frame段中,为了有源码级的调试体验于是又增加了.debug_xxx的段类型,通过dwarf语言记录了源码相关内容,由DIE作为基本单位构成
DW_CFA_advance_loc:表示此段FDE前进几个字节,后面类型解释这几字意思
DW_CFA_val_expression:后面可以跟上复杂的表达式用来计算寄存器或变变量位置。
DW_OP_constu:压入一个无符号数入栈
DW_OP_breg12 (r12):根据后续偏移和寄存器数据计算出值并压入栈中
DW_OP_plus:将栈顶两数据相加,结果入栈
DW_OP_xor:对栈顶两元素按位异或,结果入栈
DW_OP_or:按位与
这是几个dwarf该程序遇到的操作运算码,通常位于DW_CFA_val_expression标识内,该标识负责由复杂表达式计算变量或寄存器地址
程序
直接看程序只能发现4c21中存在一个对flag{}681的验证,但我们知道一般异常代码ida不会反汇编进伪代码里面,直接Tap看到外面有一个异常(倒退flag是吧😑)
可以发现关键判断为r12是否为0,但前后并未有对r12的操作,当然也可能会猜测某个时间段给了定义但一直没有使用,这就很难搞,谁会想到是栈回溯干的,当然做多了可能就有印象了,好假设我们想到了是回溯时对寄存器进行了赋值,但是如果直结搜索r12会出现很多,搜索expression字段则只剩下一个,出题人是怎么做到把它写进调试符号的呢,看雪山有一篇文章讲的是通过使用虚拟机将源程序汇编代码重构,从而实现隐藏flag加密相关代码
- 先将欲隐藏代码编译为汇编
- 汇编转为通过二叉树转为后缀表达式
- 对后缀表达式翻译为dwarf语句
- 将生成语句插入文件,利用异常时栈回溯进行执行
通过readelf -wf ezbyte_patch,最终找到:
根据该FDE的PC可以发现这个对应于判断flag{}681里的函数
wp
提炼出来
1 | DW_CFA_val_expression: r12 (r12) ( |
发现是四个寄存器相or,而且最r12 =0,则每个结果也要为零
1 | flag = "" |
moveAside
太难了,网上的题解都有点看不懂,先放这吧