0x00 程序分析
主要功能函数handler:
create函数malloc一块16字节的内存,分别存放:char* name,int price,struct * bk ,struct * fd ,由insert()函数将当前商品的结构体插入链表尾部。链表的起始位置记录在全局变量 myCart(0x0804B068)中。
delete函数进行链表的拆卸:
一开始觉得可能是一道uaf加unlink的题,后来发现整个程序没有出现过free应该是没有uaf的,delete这里的拆卸动作只是检查了目标地址必须指向有效的内存,可以利用。
最后是check out函数
0x01 利用点
通过cart函数结算总价,如果为7174就$1领iphone8,简单的枚举可以得到凑够7174的选法。而利用点就在这里,iphone 8 的结构体不是在堆中而是在栈中,也许可以有栈溢出进行覆盖的机会。
read读的机制是遇到\x00是不会停止的,也就是说my_read()函数存在栈溢出可以覆盖到iphone 8的结构体,从而覆盖fd和bk指针实现DWORD SHOOT!
0x02 leak libc
一开始我用cart作leak libc的工作,也就是将结构体的char * name 指针修改为got表中write函数的地址,这样打印时就会泄露出write实际的地址从而得到libc的基址
但是如果想继续覆盖fd和bk指针,在函数退出时执行到:
栈上本来保存一块地址的地方被我们输入的数据覆盖,导致了内存访问错误。
之后考虑在delete函数中搞事情:
首先泄露libc的原理与之前在cart中一样,我们可以在read时输入‘27’+payload,atoi函数进行解析时只会提取出27作为返回值,后面的payload由于不是ascii码范围所以不会影响其正常工作。
这里我选择puts函数的实际加载地址进行泄露:
0x03 DWORD SHOOT
RELRO不是full说明GOT表还是可以修改的,思路是用unlink来修改got表
这里触发了一个错误segment fault
重新分析unlink的过程,发现问题所在:
我们使用了第一次的来把bk写入fd+0x8,但是同时也应该保证bk+0xc的位置是可写入的,这里试图想libc_system的位置写入产生了错误。
参考别人的思路,大概有两种。
第一种比较巧妙和优雅,也就是将ebp指向的4字节覆盖为aoti GOT+0x22,这样在delete函数退出执行到leave的时候,先mov esp ,ebp,再pop ebp的时候就会把atoi+0x22赋给handler的ebp
再重新my_read的时候就会变成向atoi在got表中的地址写入数据,我们这时候就可以写入system_addr,并且可以在system地址后面直接缀上’;/bin/bash',这样等到执行下面的atoi时实际执行的就是system,而参数则是p32(system_addr)+’;/bin/bash’ 这样截断bin/bash的姿势也用了好几次了,类似的还有&&等方式。
这种方法优点在于巧妙优雅,但是可能相应的适用范围比较小,所以还学习了一下另一种比较普适的思路,也就是覆盖ebp然后通过leave来修改函数执行流程
一个简单的例子是pwnable.kr上面的一道login,建议还是自己调试下跟一遍过程
思路就是用handler里面的nptr的地址覆盖handler的ebp
这样在退出handler函数时leave指令把ebp赋给esp,输入的nptr就变成了栈顶一片内存,把0xdeadbeef pop给ebp后ret时,esp就指向我们的system函数了。
今天做swpu的ctf又被pwn题教育了><还是要继续学习的
网友评论