羊城杯 re_pwn
记一次坑爹的house of force
首先程序的逻辑很清楚:
add()限制size大小为0~0x68,dele()存在double free,show函数先允许向stack上输入,之后进行加密输出。
程式唯一的输出就是加密后的输出,因此此处是leak地址的地方,如果我们不输入的话加密的内容就是存在stack上的内容,通过解密可以拿到地址。
1 | pwndbg> stack 40 |
可见通过解密可以得到stack地址和libc地址。
加密算法为:
1 | __int64 __fastcall sub_E95(_BYTE *a1, int a2, __int64 a3) |
发现程序在调用加密函数前也有4个key,而且只是MX和DELTA不同,可认定是btea算法改的,因此写出解密脚本为:
1 |
|
编译为ELF再process进来即可解密。
之后的利用思路就很明显的hof了,先double free把堆申请到栈上,然后rop读flag。
要注意的是:heap大小最大0xx68不够用来完成rop,因此要先构造一次read以读入rop。
第一次覆盖返回地址是在read写content的时候,由于call read时将返回地址push rsp,之后并没有扩展栈帧的操作,因此之后将对应存放ret_addr的地方覆盖成执行gadget的地址即可。
最后exp:
1 | from pwn import * |