Pwn基础入门小知识
PWN小知识
由于pwn相关的一些专业术语新手入门时不易了解(我也是),因此在此写下零零碎碎(有错误请在评论区指出或补充),并且还有一些相关容易忘记的命令(多看多用)
NX
即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。
NX位(No-eXecute),也称为XD位(eXecute Disable),是现代CPU提供的一个硬件安全特性,用于标记内存页是否可以执行代码。启用NX位可以提高操作系统的安全性,因为它可以防止攻击者将数据区域(如栈或堆)中的代码作为执行指令。
当NX位启用时:
- 数据执行保护(DEP):操作系统可以利用NX位来实现数据执行保护(DEP),防止在非执行内存区域(如默认的栈和堆)执行代码。
- 防止缓冲区溢出攻击:这使得缓冲区溢出和某些类型的内存损坏攻击更加困难,因为即使攻击者能够将恶意代码注入到一个程序的内存空间,也不能执行注入的代码,因为内存页不允许执行。
- 与ASLR协同工作:NX位通常与地址空间布局随机化(ASLR)结合使用,以进一步提高安全性。
在大多数现代操作系统中,NX位默认是启用的。例如,在Linux系统中,可以通过执行dmesg | grep NX
来检查NX位是否启用。如果看到输出中有”NX (Execute Disable) protection: active”这样的信息,就表示NX位是启用的。
在编译程序时,可以使用特定的编译器选项来确保生成的二进制文件与NX位特性兼容,例如在GCC中使用-z noexecstack
选项可以防止栈被标记为可执行,这样就可以利用NX位提供的保护。
Canary
表示栈保护功能有没有开启。栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行。当启用栈保护后,函数开始执行的时候会先往栈里插入cookie信息,当函数真正返回的时候会验证cookie信息是否合法,如果不合法就停止程序运行。
在计算机安全领域,”canary”(金丝雀)一词通常指的是”栈金丝雀”,这是一种用于检测和防止缓冲区溢出攻击的保护措施。栈金丝雀是一个已知的值,它被放置在栈上的局部变量和控制数据(如返回地址)之间。其思想是,如果发生缓冲区溢出,并且覆盖了返回地址,那么在覆盖返回地址之前,这个金丝雀值也会被覆盖。
在函数调用结束之前,程序会检查栈金丝雀的值是否发生改变。如果金丝雀值被覆盖,程序就知道发生了栈溢出攻击,并且可以采取措施,通常是立即终止程序,以防止攻击者执行任意代码。这种方法是一种普遍的安全防护措施,被广泛应用于现代操作系统和编译器中。
当你看到”Canary found”这样的信息时,可能是在描述一个安全检查机制发现了栈金丝雀的值已经被篡改,从而检测到了潜在的攻击。
GOT和PLT不为人知的关系
在ELF(Executable and Linkable Format)文件中,GOT(Global Offset Table)和PLT(Procedure Linkage Table)协同工作以支持动态链接。它们通常用于动态链接库(shared libraries)中的函数调用。
这里是它们如何工作的简要概述:
- PLT (Procedure Linkage Table): 当你的程序调用一个动态链接库(如 libc)中的函数时,它实际上首先调用的是PLT中的一个”桩”(stub)。这个桩是一个小的代码片段,它跳转到GOT中的一个特定条目。
- GOT (Global Offset Table): GOT包含了函数和变量的地址。在程序第一次调用外部函数时,GOT中相应的条目被设置为指向PLT中的另一个条目,该条目将控制权转交给动态链接器,它将查找真正的函数地址,然后更新GOT中的条目以指向该地址。这意味着在第一次调用之后,GOT条目会被更新,以后的每次调用都会直接跳转到实际的函数地址,而不再经过PLT。
因此,回答你的问题:在程序启动时,GOT表上的函数地址并不存储PLT函数的地址,而是存储一个指向动态链接器进行符号解析的地址。一旦符号(例如函数)被解析,GOT表中的条目会被更新为指向实际的函数地址。这个过程被称为懒惰绑定(lazy binding),因为符号解析是在运行时按需进行的。
简而言之,GOT最初包含指向PLT中代码的指针,用于触发动态解析。解析完成后,GOT会被更新为指向实际的函数地址。
RELRP
Full RELRO(完全的重定位只读)和Partial RELRO(部分的重定位只读)是Linux系统中用来提高二进制程序安全性的技术。它们控制程序启动时动态链接器如何处理全局偏移表(GOT)和过程链接表(PLT)。以下是它们之间的主要区别:
Partial RELRO
- GOT保护: Partial RELRO不会将GOT设置为只读,这意味着程序运行时GOT中的条目可以被修改。
- 性能: 通常比Full RELRO有更好的性能,因为它允许延迟绑定,即在函数第一次被调用时才解析其地址。
- 安全性: 提供了一定程度的保护,但不如Full RELRO强。
- 启动时间: 启动时间较短,因为不需要在程序启动时立即解析所有的动态符号。
Full RELRO
- GOT保护: 将GOT设置为只读,防止攻击者在运行时修改GOT中的条目。
- PLT和GOT分离: PLT条目在程序启动时就被解析并填充到GOT中,之后GOT被标记为只读。
- 性能: 可能会有轻微的性能损失,因为启动时需要解析所有动态链接的函数地址。
- 安全性: 提供更高水平的安全性,防止了GOT覆写攻击,这是一种常见的利用技术。
- 启动时间: 启动时间可能会稍长,因为需要在程序执行前解析所有的动态符号。
总的来说,Full RELRO提供了更高级别的安全保护,但可能会以轻微增加的启动时间和潜在的运行时性能开销为代价。Partial RELRO则提供了一个折中方案,它比没有RELRO的情况更安全,但提供的保护不如Full RELRO全面。
在编译时,可以使用以下GCC链接器选项来指定RELRO的级别:
- Partial RELRO:
-Wl,-z,relro
- Full RELRO:
-Wl,-z,relro -Wl,-z,now
选择哪种级别取决于你对安全性和性能的需求。对于安全性要求高的应用程序,推荐使用Full RELRO。
ASLR
ASLR 是地址空间布局随机化(Address Space Layout Randomization)的缩写,是操作系统用来提高安全性的一种技术。ASLR 通过随机分配系统和程序的内存地址,使得攻击者很难预测和利用固定的地址来执行恶意操作。
以下是关于 ASLR 的一些关键点:
- 随机化:ASLR 会随机化进程内存布局的关键区域的位置,例如可执行文件的基址、堆栈、堆和库的位置。
- 防止利用漏洞:ASLR 的主要目的是减少依赖于已知内存地址的攻击,如缓冲区溢出、返回到库函数攻击等。
- 实现方式:ASLR 由操作系统内核实现,通常对应用程序是透明的。但是,为了有效利用 ASLR,应用程序和系统库需要编译为位置无关代码(Position Independent Code,PIC)。
- 兼容性问题:虽然 ASLR 可以提高安全性,但有时也会导致一些假设地址不变的程序出现问题。开发者需要确保他们的程序能够适应随机化的地址。
- 绕过技术:尽管 ASLR 非常有效,但它并非万无一失。攻击者已经开发出了绕过 ASLR 的技术,比如通过暴力破解内存地址或使用信息泄露来发现进程的基址。
- 可配置性:在许多系统中,ASLR 可以根据需要进行配置甚至禁用。例如,在 Linux 系统中,
/proc/sys/kernel/randomize_va_space
文件用于控制 ASLR 的使用。 - 栈保护和DEP:ASLR 通常与其他安全机制如栈保护和数据执行保护(Data Execution Prevention,DEP)一起使用,形成对攻击的更全面的防御。
PIE
简单来说pie就是指硬盘到可执行文件的映射 如果no pie那么映射就没有随机化
PIE代表“位置独立可执行文件”(Position Independent Executable)。这是一种编译选项,可以使得生成的可执行文件在内存中的加载位置可以变化,而不是固定的。位置独立的代码(PIC)通常用于共享库(shared libraries),以便库可以被加载到任何内存地址,而不需要额外的重定位开销。PIE将这一概念扩展到了整个可执行文件。
启用PIE的主要优点是提高了安全性,特别是与地址空间布局随机化(ASLR)一起使用时。ASLR可以随机化进程的内存布局,但如果可执行文件不是位置独立的,那么它的代码段通常会被加载到内存中的固定地址。这可能会使得某些类型的攻击(如基于内存地址的攻击)更容易执行。PIE使得整个可执行文件可以被加载到随机的地址,从而增加了攻击者成功利用内存漏洞的难度。
以下是PIE的一些关键特性:
- 内存随机化:PIE允许操作系统在每次运行程序时将其加载到内存中的随机位置,这增加了攻击者预测程序内存布局的难度。
- 与ASLR的结合:PIE是ASLR有效的关键组成部分。没有PIE,ASLR对于可执行文件的代码段的随机化就不会那么有效。
- 性能开销:尽管现代处理器和操作系统已经对此进行了优化,但位置独立的代码可能会引入轻微的性能开销,因为它需要在运行时进行额外的地址计算。
- 链接选项:在GCC中,可以通过添加
-fPIE
(用于编译)和-pie
(用于链接)选项来生成PIE。
例如,使用以下命令编译和链接一个程序:
1 | gcc -fPIE -pie -o my_program my_program.c |
- 广泛支持:大多数现代操作系统和编译器都支持PIE,使其成为提高软件安全性的标准做法。
总的来说,PIE是现代软件安全的重要特性,它与ASLR等技术结合,有效地提高了操作系统的抵抗远程代码执行攻击的能力。
ASLR影响的是堆,共享库,栈等等
PIE影响的是ELF本身的映射
ROPgadget
1 | ROPgadget --binary rop --only 'pop|ret' | grep 'eax' |
1 | ROPgadget --binary ret2libc1 --string '/bin/sh' |
一些ASCII码对应的字符
可能有人觉得没用,我觉得在gdb的时候还是有一点点用的,因此写下,可能也是本人水平低下
十进制 | 十六进制 | 控制字符 | 转义字符 | 说明 | Ctrl + 下列字母 |
---|---|---|---|---|---|
0 | 00 | NUL | \0 | Null character(空字符) | @ |
1 | 01 | SOH | Start of Header(标题开始) | A | |
2 | 02 | STX | Start of Text(正文开始) | B | |
3 | 03 | ETX | End of Text(正文结束) | C | |
4 | 04 | EOT | End of Transmission(传输结束) | D | |
5 | 05 | ENQ | Enquiry(请求) | E | |
6 | 06 | ACK | Acknowledgment(收到通知/响应) | F | |
7 | 07 | BEL | \a | Bell(响铃) | G |
8 | 08 | BS | \b | Backspace(退格) | H |
9 | 09 | HT | \t | Horizontal Tab(水平制表符) | I |
10 | 0A | LF | \n | Line feed(换行键) | J |
11 | 0B | VT | \v | Vertical Tab(垂直制表符) | K |
12 | 0C | FF | \f | Form feed(换页键) | L |
13 | 0D | CR | \r | Carriage return(回车键) | M |
14 | 0E | SO | Shift Out(不用切换) | N | |
15 | 0F | SI | Shift In(启用切换) | O | |
16 | 10 | DLE | Data Link Escape(数据链路转义) | P | |
17 | 11 | DC1 | Device Control 1(设备控制1) /XON(Transmit On) | Q | |
18 | 12 | DC2 | Device Control 2(设备控制2) | R | |
19 | 13 | DC3 | Device Control 3(设备控制3) /XOFF(Transmit Off) | S | |
20 | 14 | DC4 | Device Control 4(设备控制4) | T | |
21 | 15 | NAK | Negative Acknowledgement(拒绝接收/无响应) | U | |
22 | 16 | SYN | Synchronous Idle(同步空闲) | V | |
23 | 17 | ETB | End of Trans the Block(传输块结束) | W | |
24 | 18 | CAN | Cancel(取消) | X | |
25 | 19 | EM | End of Medium(已到介质末端/介质存储已满) | Y | |
26 | 1A | SUB | Substitute(替补/替换) | Z | |
27 | 1B | ESC | \e | Escape(溢出/逃离/取消) | [ |
28 | 1C | FS | File Separator(文件分割符) | \ | |
29 | 1D | GS | Group Separator(分组符) | ] | |
30 | 1E | RS | Record Separator(记录分隔符) | ^ | |
31 | 1F | US | Unit Separator(单元分隔符) | _ | |
32 | 20 | SP | White space | [Space] | |
127 | 7F | DEL | Delete(删除) | ? |