去年出了两道,已经没多少印像了,题在nssctf可以拿到

BabyRe

给了一个xml文件,用浏览器打开可以直接看到源代码,之前一直只知道xml是用来传输数据的不知道具体是怎么使用和打开

百度后知道,xml类似html,和js,是一种可以自己创建元素标识的可扩展标记语言,而html他们是预标记,元素类型文字都是已经定义好的,所以照我的理解,每个xml文件都应该是有它的特定的编码和解析的脚本,不存在说通用的软件或者程序可以直接运行它,可以使用java调用dom库对xml中元素提取并且处理,实际上看作文件读取的实例化的数据结构或者其他

image-20240426184304369

打开后,找了半天发现开始有一串链接,可以推测出这个文件是该网站的脚本文件(事实上没做过的话很难推测出,多试试总会撞出来的😑)

脚本分析

在网站找到导入后导入文件,发现这是一个少儿编程的类似模块组建的网站,有点像国内的编程猫等软件

image-20240426192249347

  • 可以发现他是对输入从下标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
2
3
4
5
6
7
8
9
10
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]
a =[102]
for i in range(1,len(flag)-1):
flag[i] ^=flag[i-1]
a.append(flag[i])
for j in a:
print(chr(j),end="")
print('}')

#flag{12307bbf-9e91-4e61-a900-dd26a6d0ea4c}

ezByte

分析

这道题当时看的时候完全没有头绪,找不到入口点,后面看师傅们的题解才知道自己对调试这一块的东西了解的太少了

dwarf

程序的编写通常除了编译外我们还需要不断修改,如果只是静态的看很多bug很难找出来,于是又有了调试器,但调试器又该怎么工作呢,最开始是利用CFA相关伪代码,但之后发现远远不够具体,也并不能恢复所有的寄存器,于是又有了dwarf,此时rbp也可以独立出来不必继续承担保留栈底地址了,一般情况下被保留在.en_frame段中,为了有源码级的调试体验于是又增加了.debug_xxx的段类型,通过dwarf语言记录了源码相关内容,由DIE作为基本单位构成

image-20240512003249280

  • 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标识内,该标识负责由复杂表达式计算变量或寄存器地址

程序

image-20240512003648183

直接看程序只能发现4c21中存在一个对flag{}681的验证,但我们知道一般异常代码ida不会反汇编进伪代码里面,直接Tap看到外面有一个异常(倒退flag是吧😑)

image-20240512004008328

可以发现关键判断为r12是否为0,但前后并未有对r12的操作,当然也可能会猜测某个时间段给了定义但一直没有使用,这就很难搞,谁会想到是栈回溯干的,当然做多了可能就有印象了,好假设我们想到了是回溯时对寄存器进行了赋值,但是如果直结搜索r12会出现很多,搜索expression字段则只剩下一个,出题人是怎么做到把它写进调试符号的呢,看雪山有一篇文章讲的是通过使用虚拟机将源程序汇编代码重构,从而实现隐藏flag加密相关代码

  • 先将欲隐藏代码编译为汇编
  • 汇编转为通过二叉树转为后缀表达式
  • 对后缀表达式翻译为dwarf语句
  • 将生成语句插入文件,利用异常时栈回溯进行执行

通过readelf -wf ezbyte_patch,最终找到:

image-20240512010838313

根据该FDE的PC可以发现这个对应于判断flag{}681里的函数

wp

提炼出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
DW_CFA_val_expression: r12 (r12) (
DW_OP_constu: 2616514329260088143
DW_OP_constu: 1237891274917891239
DW_OP_constu: 1892739
DW_OP_breg12 (r12): 0
DW_OP_plus
DW_OP_xor
DW_OP_xor
DW_OP_constu: 8502251781212277489
DW_OP_constu: 1209847170981118947
DW_OP_constu: 8971237
DW_OP_breg13 (r13): 0
DW_OP_plus
DW_OP_xor
DW_OP_xor
DW_OP_or
DW_OP_constu: 2451795628338718684
DW_OP_constu: 1098791727398412397
DW_OP_constu: 1512312
DW_OP_breg14 (r14): 0
DW_OP_plus
DW_OP_xor
DW_OP_xor
DW_OP_or
DW_OP_constu: 8722213363631027234
DW_OP_constu: 1890878197237214971
DW_OP_constu: 9123704
DW_OP_breg15 (r15): 0
DW_OP_plus
DW_OP_xor
DW_OP_xor
DW_OP_or)

发现是四个寄存器相or,而且最r12 =0,则每个结果也要为零

1
2
3
4
5
6
7
8
9
10
11
12
13
14
flag = ""
r12 = (2616514329260088143 ^ 1237891274917891239) - 1892739
r13 = (8502251781212277489 ^ 1209847170981118947) - 8971237
r14 = (2451795628338718684 ^ 1098791727398412397) - 1512312
r15 = (8722213363631027234 ^ 1890878197237214971) - 9123704
print(hex(r12) +"-" +hex(r13) +"-" +hex(r14) +"-" +hex(r15))
#0x3562666539303665-0x65342d653037652d-0x2d393663612d3439-0x6336396431336361
#狗币这里还有一个小端序的存在,需要重构字符串
str = "65363039656662352d653730652d346539342d616336392d6163333164393663"
for i in range(0, len(str), 2):
byte = bytes.fromhex(str[i:i + 2])
flag += byte.decode("utf-8")
print(flag)

moveAside

太难了,网上的题解都有点看不懂,先放这吧