2019-4-6-pwnable.kr-unlink
这一题第一眼看过去以为很简单,结果因为对指针的不熟悉导致卡壳了好久。
先用
scp -P 2222 unlink@pwnable.kr:/home/unlink/unlink 本地目录地址
把unlink和unlink.c下载下来
1 |
|
程序很简单,就是malloc了三个结构体,
在堆上的抽象结构
chunk A size
chunk A context(0-3字节存储chunk B,4-7字节为空,+8字节buf)
chunk B size
chunk B context(头8个字节分别存储着 *chunk A、 *chunk B,+8字节buf)
chunk C size
chunk C context(第4-8字节存储着chunk B,+8字节buf)
实际结构
这里有个小问题,可能因为我的kali是64位的,所以在本地的堆是按16位对齐的,而pwnable.kr服务器的堆则是按照8位对齐的,这一点我也是多次失败看别人的题解才发现的,具体原理不懂。
然后unlink(B),简单来讲就是,让A原本为空的第4-8字节变成C,C原本为空的头四个字节变成A,是一个简化版的模拟unlink
B->fd->bk=B->bk
B->bk->fd=B->fd
原本光这样是没什么漏洞的,但因为unlink之前有个gets(A->buf),gets这个函数的危险性就在于它不会检测边界,可以随意地溢出。
通过溢出覆盖B的fd和bk,就可以造成任意地址写入。
我一开始的想法是让chunk B的fd=shell()函数地址,bk=main函数返回地址,然后发现了一个问题,就是*fd+4位置会被写入bk的值,这样shell函数就被破坏了。
然后我想到先把shell地址存起来,通过调用这个存放地址来调用shell函数,于是我写了这个payload:’a’*24+p32(heap+0x28)+p32(stack+0x18)+p32(shell_addr),其中heap、stack是程序自己告诉我们的两个值,heap+0x28是chunkB的buf字段,stack+0x18是存放return地址。
这里就体现了我对指针的不熟悉,BK=stack+0x18,然后BK->fd=FD,这个时候return地址就变成了heap+0x28,然而heap+0x28不是shell的地址,而是存储着shell的地址,因为对指针的不熟悉导致我在这里卡了很久
用objdump -D unlink看汇编码
1 | call unlink |
忍不住看了别人的题解才发现函数返回之前,esp的值会变成[ecx-4],而[heap+0x28]就是shell()函数地址。retn相当于pop eip,执行retn的时候就会把栈顶的esp赋值给eip,然后实现跳转。
所以我们要让ecx-4=shell_addr=heap+0x28,因为ecx=[ebp+var_4]=[ebp-4] (var_4=-4),所以要让ebp-4地址所在的值变成(heap+0x28)+4.
这样我们就能构造payload=’a’24+p32(heap+0x28+4)+p32(stack+0x14-4)+p32(shell_addr)或者’a’24+p32(stack+0x14-8)+p32(heap+0x28+4)+p32(shell_addr)
1 | from pwn import * |
心得体会:还是看汇编靠谱
参考题解:https://www.cnblogs.com/p4nda/p/7172104.html
Linux堆溢出漏洞利用之unlink:
https://www.cnblogs.com/alisecurity/p/5563819.html
评论加载中