HXCTF-2025-pwn
final
alongrop
ida分析

1.打开第一眼,左边函数特多,加载特慢。静态编译的文件
2.如图框出部分,提示ROPchain。同时0x256字节的输入,显然是ROP。
3.最后,标记出偏移是0x40+0x8
gdb & ROPgadget 分析
ROPgadget --binary alongrop --ropchain
使用命令查看一下ropchain
1 | - Step 5 -- Build the ROP chain |
1.有可以直接写的ROPchain,但是应该不行,因为太长了。我们可以搜寻一下pop_rax;ret,直接将rax设置为0x3b,这样可以减少很多字节。
2.然后不要忘记输入ROPchain前有0x40+0x8的垃圾数据要填充。
exp
1 | from pwn import * |
secret
ida分析
先进行了一下小小的逆向,把一些变量和函数名字改了一下
main函数分析

1.第一眼看到输入赋值给v3,但v3是数组。v3[0]是我们的选项
2.关于后续功能的实现有猫腻,funcs[v3[0]-1]().稍微有点经验就能看出来,这是在调用funcs[]中的函数,那么funcs中到底有什么呢?跟进去看看。
funcs数组分析

1.对ida熟悉一点,就知道这里存放的是函数的地址,分别就是menu中三个选项对应的函数。
2.所以假设前面的v3=1,那么就会执行funcs[0],也就是加密。
3.理清了程序执行功能的逻辑,再来看每个功能。这题最关键的事encrypt,我在这里就自分析这个。
encrypt分析

1.首先会往abcd这里读入0x50字节的数据。
2.然后会对这些数据作加密处理,而加密的方式是与某个数组中的一个数,按位异或。
3.知道按位异或的作用,a^b=c ==> a=b^c,因此,加密的结果再加密,就是原值。
4.用来加密的数组就是funcs图中的s1yner
5.abcd同样位于data段,并且里funcs很近。
思路分析
1.第一个想法是通过Encrypt中的溢出,覆盖掉funcs的函数,为backdoor(题目留的后门函数,可以cat flag)。但是只有0x50字节,不够,只能刚好写满abcd那个数组。这里意识到,我们只能把后门写在abcd这个数组上。所以应该考虑有没有办法,访问到这里呢?
2.继续回去观察main函数,看到输入后会检测v3是否大于3。也就是小于等于3,都是合法的输入。试想,如果输入0,那么最后就是func[-1](),也就是会调用我们最后输入的8字节的地址。因此,我们可以输入0 和 负数,来访问abcd上的地址。只要对应上。
3.那接下来就是解决,加密的问题。很简单,将log_level设置为debug,发送正常的backdoor地址,看看返回的加密内容是什么。然后手敲一下backdoor的地址,把加密后的内容作为原文发送,那么正确的地址就会在加密后被写上去。
gdb分析
加密内容获取

1.直接发送p64(backdoor),查看加密的内容。
2.从后往前数,因为后面紧跟的是1.Encrupt......,从0x31 往前数8个字节,就是我们要的内容,然后直接发这个就行。
exp
1 | from pwn import * |
flagreader
ida分析
main函数分析

1.开幕雷击,直接就是一个gift给我们。显然是一个地址,可能需要这个地址泄露一些东西。
2.同时还有两个函数,一个readflag,一个vuln。直接跟进。
readflag函数分析


1.首先看伪代码,发现是把flag读取了0x50字节,写在了&_bss_start[6]._IO_read_end上。但是这个,到底是哪个地址呢?
2.观察汇编的代码,可以看到rsi也就读入的地址是rcx,而rcx 又是 rax+0x520,rax又是__bss_start.所以可以知道rsi=__bss_start+0x520.
3.而我们的gift就是__bss_start.
vuln函数分析

1.非常明显的格式化字符串漏洞,结合上文。第一个想到把flag的地址写入,同时用”%s”对flag内容进行打印。
2.64位要加上6,因为有前6个寄存器。最后的偏移还是需要gdb查看。因为可以输入0x10,所以可以把__bss_start+0x520布置在下面。
gdb分析

1.找到printf函数的栈帧,可以看到我们的输入是在偏移为0 的位置,加上6就是6.
2.把地址写在下面的话,偏移就是7。
exp
1 | from pwn import * |



