看一道Pwn题练习一下
参考文章:https://veritas501.space/2017/03/10/JarvisOJ_WP/ v爷爷nb
没有开启PIE,不错
程序一共有五个功能,本身没有后门函数给我们利用,要泄露地址,在堆上泄露地址还从来没尝试过(因为我不会)
在bss字段0x6020A8处,会有一个指针指向一开始创建的堆首地址
我们结合new操作以及list操作的函数,其实可以把整个guestbook的结构体分析出来
1 | struct chunk_list // size 0x1810 |
接下来就是在各个函数中找漏洞了
Delete函数
1 | int Delete() |
Edit函数
1 | int Edit() |
接下来打算一边写exp,一边写注释来理解,毕竟我是真的不懂堆
leak
先来第一个步骤吧,就是leak出heap的base地址
1 | #coding=utf8 |
unlink
接下来就是unlink了,几个月前我曾尝试弄懂,可惜我失败了
这里最开始创建的大小的0x80,128个字节,所以之后realloc后,还是当作fast bin来处理
free时的操作
1 | free(chunk) |
这其实就涉及到了unlink时可能会进行的合并操作
1)检查是否可以向后合并
首先需要检查 previous chunk 是否是空闲的(通过当前 chunk size 部分中的 flag 最低位去判断),在默认情况下,堆内存中的第一个chunk总是被设置为allocated的,即使它根本就不存在。
如果为free的话,那么就进行向后合并:
1)将前一个chunk占用的内存合并到当前chunk;
2)修改指向当前chunk的指针,改为指向前一个chunk。
3)使用unlink宏,将前一个free chunk从双向循环链表中移除。
前一个 chunk 是正在使用的,不满足向后合并的条件。
2)检查是否可以向前合并
在这里需要检查 next chunk 是否是空闲的(通过下下个 chunk 的flag的最低位去判断),在找下下个chunk(这里的下、包括下下都是相对于 chunk first 而言的)的过程中,首先当前 chunk+ 当前 size 可以引导到下个 chunk ,然后从下个 chunk 的开头加上下个 chunk 的 size 就可以引导到下下个 chunk 。
如果我们把下个 chunk 的 size 覆盖为了-4**(32位),那么它会认为下个 chunk 从 prev_size 开始就是下下个chunk了,既然已经找到了下下个 chunk ,那就就要去看看 size 的最低位以确定下个 chunk 是否在使用,当然这个 size 是 -4(11111100补码)** ,所以它指示下个 chunk 是空闲的。
在这个时候,就要发生向前合并了。即 first chunk 会和 first chunk 的下个 chunk (即 second chunk )发生合并。在此时会触发 unlink(second) 宏,想将 second 从它所在的 bin list 中解引用。
相关链接:https://www.jianshu.com/p/2776b6a79a11
如今的unlink
1 | unlink(P, BK, FD) { |
道高一尺魔高一丈,精心伪造一个chunk,使FD->bk和BK->fd=P,这可以通过unlink检查
继续我们的exp,最后getshell
1 | # unlink |
本文链接: http://woaixiaoyuyu.github.io/2019/02/09/Jarvis%20OJ---Guestbook2%20WP/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!