pwnable.tw hacknote wp
pwnable.tw上hacknote的wp
程序分析
保护
1 | Arch: i386-32-little |
程序有三个基本操作,add、delete、print笔记,其中delete中free后没有把指针置为null,可创造一个迷途指针,导致了uaf漏洞
add note功能:
看到malloc了8字节的一个结构体,分别存放函数地址0x804862b(打印content的内容)和一个指向当前note内容content的指针
1 | struct note{ |
而后根据size再申请新的空间:
1 | v0 = ptr[i]; |
基本的思路是先add 两次,但是内容的大小不能是8字节,不然会分配4个 16字节的fast bin;然后再delete两次,此时 fast bin链表如图:
因为prev_size 和 size 在 32 位下占 8 bytes ,所以结构体的实际堆块大小为 16 bytes。在申请 content 内容时要大于 16 bytes。
这里需要了解malloc内存对齐的知识:
在32位下malloc的最小分配单位为16字节,64位下最小分配单位为32字节,其中request2size就是malloc的内存对齐操作。
从request2size还可以知道,如果是64位系统,申请内存为1 ~ 24字节时,系统内存消耗32字节,当申请内存为25字节时,系统内存消耗48字节。 如果是32位系统,申请内存为1 ~ 12字节时,系统内存消耗16字节,当申请内存为13字节时,系统内存消耗24字节。(类似计算MINSIZE)
利用思路:
- add_note首先malloc出8字节来存放note结构体,接着用户输入content的size:16,这样操作两次,分配的内存大小为16->24->16->24
- delete_note来释放内存,delete_note(0),delete_note(1)
接着add_note,增加一个content size=8,内容为’ccccdddd’ - 因此新建的note2的strcut note将被分配到note1的结构体位置,note2的content将被分配到note0的结构体位置,note0八字节的结构体处分别存放了打印函数0x804862b和其参数地址,现在将被输入的content覆盖,再执行print(0),覆盖的函数和内容就会执行。
调试
添加两个note后的堆
free两个note后的堆
再添加note2为ccccdddd
可以看到strcut note0结构体的putnote和text指针已经被覆盖成了cccc、ddddd
泄露libc:
题目已经给出了libc文件,我们要泄露出libc加载到内存中的基址:
以read()为例,我们将指向content的指针覆盖为read在got表中的地址,这样调用print_note后就会打印出read的实际地址。
再利用:system_addr-libc_system=read_addr-libc_read
得到 system_addr=read_addr-libc_read+libc_system
到了system的实际地址,只需要重复相同的步骤,只是将原本0x804862b覆盖为system的地址,就可以get system了。
注意点:覆盖后system的参数实际上是从note0结构体开始的,也就是p32(system_addr)+’sh’,这样是无法达到system(‘/bin/sh’)的效果的,要用到system参数截断的姿势,当时用的是&&sh,类似的还有||sh
,;sh;
最终exp:
1 | from pwn import * |
参考
https://blog.csdn.net/qq_35429581/article/details/78231443
http://www.carlstar.club/2019/03/01/hacknote/