目的:需要构造ROP链来调用三个函数,并传入正确的参数。
在callme_one函数中是读取文件encrypted_flag.dat并保存到堆分配的空间g_buf中;callme_two函数读取文件key1.dat和g_buf进行逐字节异或解密;callme_three函数读取文件key2.dat继续和g_bug进行异或解密;
三个函数都会对传入的参数进行判定,参数符合条件再进行解密操作:
- callme_one:arg1 == 0xDEADBEEF && arg2 == 0xCAFEBABE && arg3 == 0xD00DF00D
- callme_two:arg1 == 0xDEADBEEF && arg2 == 0xCAFEBABE && arg3 == 0xD00DF00D
- callme_thress:arg1 == 0xDEADBEEF && arg2 == 0xCAFEBABE && arg3 == 0xD00DF00D
在IDA中可以找到一个可用的gadget,如下 :第一个gadget的作用是:分别从sp+0x10、sp+0xc、sp+0x8获取a0、a1、a2参数,传递给保存在sp+0x4处的函数,跳转并执行;1
2
3
4
5
6
7
8
9
10
11.text:00400BB0 usefulGadgets:
.text:00400BB0 10 00 A4 8F lw $a0, 0x10($sp)
.text:00400BB4 0C 00 A5 8F lw $a1, 0xC($sp)
.text:00400BB8 08 00 A6 8F lw $a2, 8($sp)
.text:00400BBC 04 00 B9 8F lw $t9, 4($sp)
.text:00400BC0 09 F8 20 03 jalr $t9
.text:00400BC4 00 00 00 00 nop
.text:00400BC4
.text:00400BC8 14 00 BF 8F lw $ra, 0x14($sp)
.text:00400BCC 08 00 E0 03 jr $ra
.text:00400BD0 18 00 BD 23 addi $sp, 0x18
第二个gadget的作用是:跳转到sp+0x14执行,并开辟0x18大小的栈帧
ROP构造
漏洞函数依旧是pwnme,ra寄存器中的函数返回地址保存在:sp+0x3C,存在溢出的缓冲区buffer:sp+0x18,因此需要0x24个字节的数据填充到返回地址。
需要注意的是,当开始执行ROP,在pwnme函数中已经将堆栈指针sp进行了恢复,因此覆盖掉返回地址后,为了后期的数据布局,还需要继续覆盖4个字节,使得随后的参数可以正确布置到栈上。
1 | # 填充到栈上的返回地址 |
exp
1 | from pwn import * |
结果如下:
1 | python3 exp.py |