Linux下的保护机制
查看程序保护
checksec 文件名
文件保护机制
在 CTF PWN 中,接触到的文件保护机制主要有五种:
- RELRO 【GOT写保护】
- Stack 【Canary 金丝雀】
- NX 【堆栈不可执行】
- PIE 【程序代码段、数据段地址随机化】
- ASLR 【内存地址随机化】
Arch
程序架构信息
执行 checksec 文件名
时,也会输出 Arch 信息,但这本身并不是保护机制
Arch 主要用于判断文件是 64 位还是 32 位,使用 Pwntools 编写 exp 使用 p64 还是 p32
ASLR
通过随机放置进程关键数据区域的地址空间来防止攻击者能可靠地跳转到内存的特定位置来利用函数
现代操作系统一般都加设这一机制,以防范恶意程序对已知地址进行 Return-to-libc 攻击
RELRO
用于加强对二进制程序数据段的保护的技术,在 Linux 系统安全领域数据可以写的存储区就会是攻击的目标,尤其是存储函数指针的区域,所以在安全防护的角度来说应当尽量减少可写的存储区域
Partial RELRO(部分开启,GOT 可写)
,易受到攻击,例如攻击者可以 atoi.got 为 system.plt,进而输入/bin/sh\x00
获得 shellFull RELRO(全部开启,GOT 不可写)
,使整个 GOT 表只读,从而无法被覆盖,意味着无法修改 GOT 表。但这样会大大增加程序的启动时间,因为程序在启动之前需要解析所有的符号
Stack
栈溢出检查,一种用来防护栈溢出的保护机制
Canary found
表示开启了 Canary 保护,不能直接用溢出的方法覆盖栈中返回地址
原理:
- 函数每一次执行时,在栈上随机产生一个 Canary 值
- 代码一般在函数的入口处,先从
FS/GS
寄存器中取出一个 4 字节 (eax) 或者 8 字节 (rax) 的值存到栈上,逆向题中的代码经常遇见 - 当函数结束时,会检查这个栈上的值是否和存进去的值一致;如果不一致,就会停止程序运行,作用相当于校验信息的 cookie
一般在覆盖返回地址的时候也会将 Canary 信息给覆盖掉,导致栈保护检查失败,阻止控制程序流程
NX
NX 将数据所在内存页标识为不可执行,当程序溢出成功转入 shellcode 时,程序会尝试在数据页面上执行指令,此时 CPU 就会抛出异常,而不是去执行恶意指令
如果这个保护开启,就意味着栈中数据没有执行权限,程序将数据段和代码段分开了,因此不能将 shellcode 写入栈中并执行;当在堆栈上写入 shellcode 并触发时,只会直接造成程序的崩溃,而不是执行 shellcode
一般可以利用 ROP 的方式绕过
PIE
PIE 在编译时将程序编译为位置无关,程序运行的各个段加载的虚拟地址在装载时确定(地址随机化),主要针对
.text(代码段)
,.data(数据段)
,.bss(未初始化全局变量段)
进行地址随机化的保护
最终决定是否随机化看 ASLR ,如果 ASLR 是关闭的,那么就算开启了 PIE 也不会进行地址随机化
程序在开启 PIE 后,IDA 中看到的地址是偏移量 offset
,真实地址 = 基地址 + 偏移量
由于内存的分页管理机制,即使地址随机化,只能影响到单个内存页,一个内存页大小为
0x1000
,那么就意味着不管地址怎么变,某一条指令的后三位十六进制数是始终不变的,也就是地址的低三位不会发生改变。有时可以利用这一点对地址进行爆破绕过方式:地址泄露、
partial write
RWX
读写权限
权限 | 解释 | |
---|---|---|
r | 对文件而言,具有读取文件内容的权限;对目录来说,具有浏览目录的权限 | |
w | 对文件而言,具有新增、修改、删除文件内容的权限;对目录而言,具有新建、删除、修改、移动目录内文件的权限 | |
x | 对文件而言,具有执行文件的权限;对目录而言该用户具有进入目录的权限 |
- 目录的只读访问不允许使用
cd
进入目录,必须要有执行的权限才能进入 - 只有执行权限只能进入目录,不能看到目录下的内容;要想看到目录下的文件名和目录名,需要可读权限
- 一个文件能不能被删除,主要看该文件所在的目录对用户是否具有写权限,如果目录对用户没有写权限,则该目录下的所有文件都不能被删除,文件所有者除外
- 目录的 w 位不设置,即使拥有目录中某文件的 w 权限也不能写该文件