diff --git a/doc/6.1.10_pwn_0ctf2017_babyheap2017.md b/doc/6.1.10_pwn_0ctf2017_babyheap2017.md index 2407cfc..d9301e9 100644 --- a/doc/6.1.10_pwn_0ctf2017_babyheap2017.md +++ b/doc/6.1.10_pwn_0ctf2017_babyheap2017.md @@ -2,6 +2,7 @@ - [题目复现](#题目复现) - [题目解析](#题目解析) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -81,6 +82,8 @@ Command: 5 怎么利用 Dump 操作呢?如果能使两个 chunk 相重叠,Free 一个,Dump 另一个,或许可行。 + +## 漏洞利用 #### leak libc 还是一样的,为了方便调试,先关掉 ASLR。首先分配 3 个 fast chunk 和 1 个 small chunk,其实填充数据对漏洞利用是没有意义的,这里只是为了方便观察: ```python diff --git a/doc/6.1.11_pwn_9447ctf2015_search_engine.md b/doc/6.1.11_pwn_9447ctf2015_search_engine.md index 525d89b..003d88a 100644 --- a/doc/6.1.11_pwn_9447ctf2015_search_engine.md +++ b/doc/6.1.11_pwn_9447ctf2015_search_engine.md @@ -2,6 +2,7 @@ - [题目复现](#题目复现) - [题目解析](#题目解析) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -63,5 +64,7 @@ n ## 题目解析 +## 漏洞利用 + ## 参考资料 - [how2heap](https://github.com/shellphish/how2heap) diff --git a/doc/6.1.12_pwn_n1ctf2018_vote.md b/doc/6.1.12_pwn_n1ctf2018_vote.md index 32c16b2..c1620da 100644 --- a/doc/6.1.12_pwn_n1ctf2018_vote.md +++ b/doc/6.1.12_pwn_n1ctf2018_vote.md @@ -2,6 +2,7 @@ - [题目复现](#题目复现) - [题目解析](#题目解析) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -36,8 +37,8 @@ $ socat tcp4-listen:10001,reuseaddr,fork exec:"env LD_PRELOAD=./libc-2.23.so ./v ## 题目解析 -#### Exploit +## 漏洞利用 ## 参考资料 https://ctftime.org/task/5490 diff --git a/doc/6.1.13_pwn_34c3ctf2017_readme_revenge.md b/doc/6.1.13_pwn_34c3ctf2017_readme_revenge.md index c033f7d..8c4601f 100644 --- a/doc/6.1.13_pwn_34c3ctf2017_readme_revenge.md +++ b/doc/6.1.13_pwn_34c3ctf2017_readme_revenge.md @@ -2,7 +2,7 @@ - [题目复现](#题目复现) - [题目解析](#题目解析) -- [Exploit](#exploit) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -238,7 +238,7 @@ __register_printf_specifier (int spec, printf_function converter, 然后发现 `spec` 被直接用做数组 `__printf_function_table` 和 `__printf_arginfo_table` 的下标。`s` 也就是 `0x73`,这和我们在 gdb 里看到的相符:`rdx=0x73`,`[rax+rdx*8]`正好是数组取值的方式,虽然这里的 `rax` 里保存的是 `__printf_modifier_table`。 -## Exploit +## 漏洞利用 有了上面的分析,下面我们来构造 exp。 回顾一下 `__parse_one_specmb()` 函数里的 `if` 判断语句,我们知道 C 语言对 `||` 的处理机制是如果第一个表达式为 True,就不再进行第二个表达式的判断,所以为了执行函数 `*__printf_arginfo_table[spec->info.spec]`,需要前面的判断条件都为 False。我们可以在 `.bss` 段上伪造一个 `printf_arginfo_size_function` 结构体,在结构体偏移 `0x73*8` 的地方放上 `__stack_chk_fail()` 的地址,当该函数执行时,将打印出 `argv[0]` 指向的字符串,所以我们还需要将 `argv[0]` 覆盖为 flag 的地址。 @@ -251,6 +251,7 @@ $ python2 exp.py *** stack smashing detected ***: 34C3_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX terminated ``` +#### exploit 完整的 exp 如下: ```python from pwn import * diff --git a/doc/6.1.14_pwn_32c3ctf2015_readme.md b/doc/6.1.14_pwn_32c3ctf2015_readme.md index 569f2e9..d27f221 100644 --- a/doc/6.1.14_pwn_32c3ctf2015_readme.md +++ b/doc/6.1.14_pwn_32c3ctf2015_readme.md @@ -2,7 +2,7 @@ - [题目复现](#题目复现) - [题目解析](#题目解析) -- [Exploit](#exploit) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -119,6 +119,8 @@ Please overwrite the flag: Thank you, bye! ``` 看注释已经很明显了,第一次的输入需要我们触发栈溢出,使程序调用 `__stack_chk_fail()`,并打印出 `argv[0]`。第二次的输入将覆盖掉位于 `0x00600d20` 的 flag。 + +## 漏洞利用 那么问题来了,如果 flag 被覆盖掉了,那还怎样将其打印出来。这就涉及到了 ELF 文件的映射问题,我们知道 x86-64 程序的映射是从 `0x400000` 开始的: ``` $ ld --verbose | grep __executable_start @@ -269,8 +271,19 @@ __libc_message (do_abort=do_abort@entry=0x1, fmt=fmt@entry=0x7ffff7b9c49f "*** % 81 ../sysdeps/posix/libc_fatal.c: No such file or directory. ``` +Bingo!!! +``` +$ python exp.py +[+] Opening connection to 127.0.0.1 on port 10001: Done +[+] Receiving all data: Done (703B) +[*] Closed connection to 127.0.0.1 port 10001 +Hello! +What's your name? Nice to meet you, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA @. +Please overwrite the flag: Thank you, bye! +*** stack smashing detected ***: 32C3_TheServerHasTheFlagHere... terminated +``` -## Exploit +#### exploit 最终的 exp 如下: ```python from pwn import * @@ -288,18 +301,6 @@ io.sendline(payload_2) print io.recvall() ``` -Bingo!!! -``` -$ python exp.py -[+] Opening connection to 127.0.0.1 on port 10001: Done -[+] Receiving all data: Done (703B) -[*] Closed connection to 127.0.0.1 port 10001 -Hello! -What's your name? Nice to meet you, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA @. -Please overwrite the flag: Thank you, bye! -*** stack smashing detected ***: 32C3_TheServerHasTheFlagHere... terminated -``` - ## 参考资料 - https://ctftime.org/task/1958 diff --git a/doc/6.1.15_pwn_34c3ctf2017_simplegc.md b/doc/6.1.15_pwn_34c3ctf2017_simplegc.md index b128dd3..0982fab 100644 --- a/doc/6.1.15_pwn_34c3ctf2017_simplegc.md +++ b/doc/6.1.15_pwn_34c3ctf2017_simplegc.md @@ -2,8 +2,7 @@ - [题目复现](#题目复现) - [题目解析](#题目解析) -- [Exploit one](#exploit-one) -- [Exploit two](#exploit-two) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -679,7 +678,7 @@ struct user *users[0x60]; 然后是删除 user 的过程中,只释放了 user 本身和 user->group,而 user->name 没有被释放。可能导致信息泄漏。 -## Exploit +## 漏洞利用 逆向分析完成,来简单地总结一下。 - 两个结构体和两个由结构体指针构成的数组: ```c @@ -706,7 +705,6 @@ struct group *groups[0x60]; // 0x6023e0 然后是关于 tcache 的问题。在这个程序中有两个线程,thread-1 为主线程,thread-2 为 GC 线程,它们都有自己的 tcache。程序中所有 chunk 的分配工作都由 thread-1 执行,thread-2 只释放(group和group_name)不分配,所以在它的 tcache bins 被装满以后所有该线程释放的 fast chunk 都被放进 fastbins 中。而 fastbins 是进程公用的,所以会被主线程在分配时使用。 -## Exploit one 第一种方法,我们利用 ref_count 溢出的 UAF。 #### overflow @@ -987,8 +985,6 @@ LD_PRELOAD=./libc-2.26.so /bin/sh ``` 应该换成 Ubuntu-17.10 试试。(本机Arch) - -## Exploit two 第二种方法,我们利用两个具有同名 group 的 user 释放时的 UAF。这种方法似乎与 tcache 的关系更大一点。 diff --git a/doc/6.1.16_pwn_hitbctf2017_1000levels.md b/doc/6.1.16_pwn_hitbctf2017_1000levels.md index 4549819..06b02db 100644 --- a/doc/6.1.16_pwn_hitbctf2017_1000levels.md +++ b/doc/6.1.16_pwn_hitbctf2017_1000levels.md @@ -2,7 +2,7 @@ - [题目复现](#题目复现) - [题目解析](#题目解析) -- [Exploit](#exploit) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -340,7 +340,7 @@ vaddr=0x00201fd0 paddr=0x00001fd0 type=SET_64 system 可以看到 `read()` 函数有一个很明显的栈溢出漏洞,`local_30h` 并没有 `0x400` 这么大的空间。由于游戏是递归的,所以我们需要答对前 999 道题,在最后一题时溢出,构造 ROP。 -## Exploit +## 漏洞利用 总结一下,程序存在两个漏洞: - hint 函数将 system 放到栈上,而 go 函数在使用该地址时未进行初始化 - level 函数存在栈溢出 @@ -448,7 +448,7 @@ $ whoami firmy ``` -#### exp +#### exploit 完整的 exp 如下: ```python #!/usr/bin/env python diff --git a/doc/6.1.17_pwn_secconctf2016_jmper.md b/doc/6.1.17_pwn_secconctf2016_jmper.md index f256b85..e64729b 100644 --- a/doc/6.1.17_pwn_secconctf2016_jmper.md +++ b/doc/6.1.17_pwn_secconctf2016_jmper.md @@ -2,7 +2,7 @@ - [题目复现](#题目复现) - [题目解析](#题目解析) -- [Exploit](#exploit) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -424,7 +424,7 @@ struct student *my_class[0x1e]; 漏洞就是在读入 memo 和 name 的时候都存在的 one-byte overflow,其中 memo 会覆盖掉 name 指针的低字节。考虑可以将 name 指针改成其它地址,并利用修改 name 的功能修改地址上的内容。 -## Exploit +## 漏洞利用 所以我们的思路是通过 one-byte overflow,使 my_class[0]->name 指向 my_class[1]->name,从而获得任意地址读写的能力。然后泄漏 system 函数地址和 main 函数的返回地址,将返回地址覆盖以制造 ROP,调用 system('/bin/sh') 获得 shell。 #### overflow @@ -550,7 +550,7 @@ $ whoami firmy ``` -#### exp +#### exploit 完整的 exp 如下: ```python #!/usr/bin/env python diff --git a/doc/6.1.18_pwn_hitbctf2017_sentosa.md b/doc/6.1.18_pwn_hitbctf2017_sentosa.md index 47a7197..0d4ee5f 100644 --- a/doc/6.1.18_pwn_hitbctf2017_sentosa.md +++ b/doc/6.1.18_pwn_hitbctf2017_sentosa.md @@ -706,7 +706,7 @@ $ whoami firmy ``` -#### exp +#### exploit 完整的 exp 如下: ```python #!/usr/bin/env python diff --git a/doc/6.1.19_pwn_hitbctf2018_gundam.md b/doc/6.1.19_pwn_hitbctf2018_gundam.md index 4adb0a2..fd36749 100644 --- a/doc/6.1.19_pwn_hitbctf2018_gundam.md +++ b/doc/6.1.19_pwn_hitbctf2018_gundam.md @@ -2,7 +2,7 @@ - [题目复现](#题目复现) - [题目解析](#题目解析) -- [Exploit](#exploit) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -687,7 +687,7 @@ $ whoami firmy ``` -#### exp +#### exploit 完整的 exp 如下: ```python #!/usr/bin/env python diff --git a/doc/6.1.1_pwn_hctf2016_brop.md b/doc/6.1.1_pwn_hctf2016_brop.md index f1ae1d5..35dbf33 100644 --- a/doc/6.1.1_pwn_hctf2016_brop.md +++ b/doc/6.1.1_pwn_hctf2016_brop.md @@ -2,7 +2,7 @@ - [题目复现](#题目复现) - [BROP 原理及题目解析](#brop-原理及题目解析) -- [Exploit](#exploit) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -69,6 +69,8 @@ BROP 即 Blind ROP,需要我们在无法获得二进制文件的情况下, 下面我们结合题目来讲一讲。 + +## 漏洞利用 #### 栈溢出 首先是要找到栈溢出的漏洞,老办法从 1 个字符开始,暴力枚举,直到它崩溃。 ```python @@ -359,6 +361,7 @@ p.recvline() p.sendline(payload) p.interactive() ``` + Bingo!!! ``` $ python2 exp.py @@ -368,8 +371,7 @@ $ whoami firmy ``` - -## Exploit +#### exploit 完整的 exp 如下: ```python from pwn import * diff --git a/doc/6.1.20_pwn_33c3ctf2016_babyfengshui.md b/doc/6.1.20_pwn_33c3ctf2016_babyfengshui.md index 260a0bf..a92e84c 100644 --- a/doc/6.1.20_pwn_33c3ctf2016_babyfengshui.md +++ b/doc/6.1.20_pwn_33c3ctf2016_babyfengshui.md @@ -364,7 +364,7 @@ store 放在 `0x804b080`,当前 user 个数 user_num 放在 `0x804b069`。 ## 漏洞利用 -所以我们首先添加两个 user,用于绕过检查。第 3 个 user 存放 "/bin/sh"。然后删掉第 1 个 user,并创建一个 description 很长的 user,其长度是第 1 个 user 的 description 长度加上 user 结构体长度。这时候检查就绕过了,我们可以在添加新 user 的时候修改 description 大小,造成堆溢出,并修改第 2 个 user 的 user->desc 为 free@got.plt,从而泄漏出 libc 地址。得到 system 地址后,此时修改第 2 个 user 的 description,其实是修改 free 的 GOT,所以我们将其改成 system@got.plt。最后删除第 3 个 user,触发 system('/bin/sh'),得到 shell。 +所以我们首先添加两个 user,用于绕过检查。第 3 个 user 存放 "/bin/sh"。然后删掉第 1 个 user,并创建一个 description 很长的 user,其长度是第 1 个 user 的 description 长度加上 user 结构体长度。这时候检查就绕过了,我们可以在添加新 user 的时候修改 description 大小,造成堆溢出,并修改第 2 个 user 的 user->desc 为 `free@got.plt`,从而泄漏出 libc 地址。得到 system 地址后,此时修改第 2 个 user 的 description,其实是修改 free 的 GOT,所以我们将其改成 `system@got.plt`。最后删除第 3 个 user,触发 system('/bin/sh'),得到 shell。 开启 ASLR。Bingo!!! ``` @@ -376,7 +376,7 @@ $ whoami firmy ``` -#### exp +#### exploit 完整的 exp 如下: ```python #!/usr/bin/env python diff --git a/doc/6.1.2_pwn_njctf2017_pingme.md b/doc/6.1.2_pwn_njctf2017_pingme.md index c9802c5..d8b1d6f 100644 --- a/doc/6.1.2_pwn_njctf2017_pingme.md +++ b/doc/6.1.2_pwn_njctf2017_pingme.md @@ -2,7 +2,7 @@ - [题目复现](#题目复现) - [Blind fmt 原理及题目解析](#blind-fmt-原理及题目解析) -- [Exploit](#exploit) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -28,6 +28,8 @@ $ socat tcp4-listen:10001,reuseaddr,fork exec:./pingme & 通常有两种方法可以解决这种问题,一种是利用信息泄露把程序从内存中 dump 下来,另一种是使用 pwntools 的 DynELF 模块(关于该模块的使用我们在章节 4.4 中有讲过)。 + +## 漏洞利用 #### 确认漏洞 首先你当然不知道这是一个栈溢出还是格式化字符串,栈溢出的话输入一段长字符串,但程序是否崩溃,格式化字符串的话就输入格式字符,看输出。 ``` @@ -86,11 +88,11 @@ payload = "%9$s.AAA" + p32(start_addr) 于是就成了有二进制文件无 libc 的格式化字符串漏洞,在 r2 中查询 printf 的 got 地址: ``` [0x08048490]> is~printf -vaddr=0x08048400 paddr=0x00000400 ord=002 fwd=NONE sz=16 bind=GLOBAL type=FUNC name=imp.printf +vaddr=0x08048400 paddr=0x00000400 ord=002 fwd=NONE sz=16 bind=GLOBAL type=FUNC name=imp.printf [0x08048490]> pd 3 @ 0x08048400 - : ;-- imp.printf: - : 0x08048400 ff2574990408 jmp dword [reloc.printf_116] ; 0x8049974 - : 0x08048406 6808000000 push 8 ; 8 + : ;-- imp.printf: + : 0x08048400 ff2574990408 jmp dword [reloc.printf_116] ; 0x8049974 + : 0x08048406 6808000000 push 8 ; 8 `=< 0x0804840b e9d0ffffff jmp 0x80483e0 ``` 地址为 `0x8049974`。 @@ -200,8 +202,7 @@ $ whoami firmy ``` - -## Exploit +#### exploit 完整的 exp 如下: ```python from pwn import * diff --git a/doc/6.1.3_pwn_xdctf2015_pwn200.md b/doc/6.1.3_pwn_xdctf2015_pwn200.md index 1cdeea3..59a1f9c 100644 --- a/doc/6.1.3_pwn_xdctf2015_pwn200.md +++ b/doc/6.1.3_pwn_xdctf2015_pwn200.md @@ -2,7 +2,7 @@ - [题目复现](#题目复现) - [ret2dl-resolve 原理及题目解析](#ret2dlresolve-原理及题目解析) -- [Exploit](#exploit) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -942,7 +942,7 @@ firmy 如果觉得手工构造太麻烦,有一个工具 [roputils](https://github.com/inaz2/roputils) 可以简化此过程,感兴趣的同学可以自行尝试。 -## Exploit +## 漏洞利用 完整的 exp 如下: ```python from pwn import * diff --git a/doc/6.1.5_pwn_grehackctf2017_beerfighter.md b/doc/6.1.5_pwn_grehackctf2017_beerfighter.md index 1ff6e9e..709da47 100644 --- a/doc/6.1.5_pwn_grehackctf2017_beerfighter.md +++ b/doc/6.1.5_pwn_grehackctf2017_beerfighter.md @@ -1,13 +1,14 @@ # 6.1.5 pwn GreHackCTF2017 beerfighter +- [题目复现](#题目复现) - [题目解析](#题目解析) -- [Exploit](#exploit) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) [下载文件](../src/writeup/6.1.5_pwn_grehackctf2017_beerfighter) -## 题目解析 +## 题目复现 ``` $ file game game: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=1f9b11cb913afcbbbf9cb615709b3c62b2fdb5a2, stripped @@ -43,6 +44,8 @@ By ! Segmentation fault (core dumped) ``` + +##题目解析 程序大概清楚了,看代码吧,经过一番搜索,发现了一个很有意思的函数: ``` [0x00400d8e]> pdf @ fcn.00400773 @@ -67,6 +70,8 @@ gdb-peda$ pattern_offset $ebp ``` 缓冲区还挺大的,`1040+8=1048`。 + +## 漏洞利用 好,现在思路已经清晰了,先利用缓冲区溢出漏洞,用 `syscall;ret` 地址覆盖返回地址,通过 frame\_1 调用 `read()` 读入 frame_2 到 `.data` 段(这个程序没有`.bss`,而且`.data`可写),然后将栈转移过去,调用 `execve()` 执行“/bin/sh”,从而拿到 shell。 构造 sigreturn: @@ -122,8 +127,7 @@ $ whoami firmy ``` - -## Exploit +#### exploit 完整的 exp 如下: ```python from pwn import * diff --git a/doc/6.1.6_pwn_defconctf2015_fuckup.md b/doc/6.1.6_pwn_defconctf2015_fuckup.md index 08cc365..daf5ea4 100644 --- a/doc/6.1.6_pwn_defconctf2015_fuckup.md +++ b/doc/6.1.6_pwn_defconctf2015_fuckup.md @@ -2,7 +2,7 @@ - [ret2vdso 原理](#ret2vdso-原理) - [题目解析](#题目解析) -- [Exploit](#exploit) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -29,8 +29,7 @@ RELRO STACK CANARY NX PIE RPATH RUNPA No RELRO No canary found NX enabled No PIE No RPATH No RUNPATH No 0 0 fuckup ``` -## Exploit -完整的 exp 如下: +## 漏洞利用 ## 参考资料 - `man vdso` diff --git a/doc/6.1.7_pwn_0ctf2015_freenote.md b/doc/6.1.7_pwn_0ctf2015_freenote.md index 2bc01f1..db976a7 100644 --- a/doc/6.1.7_pwn_0ctf2015_freenote.md +++ b/doc/6.1.7_pwn_0ctf2015_freenote.md @@ -1,14 +1,14 @@ # 6.1.7 pwn 0CTF2015 freenote -- [题目简介](#题目解析) -- [题目逆向](#题目逆向) -- [Exploit](#exploit) +- [题目复现](#题目复现) +- [题目解析](#题目解析) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) [下载文件](../src/writeup/6.1.7_pwn_0ctf2015_freenote) -## 题目解析 +## 题目复现 ``` $ file freenote freenote: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=dd259bb085b3a4aeb393ec5ef4f09e312555a64d, stripped @@ -105,7 +105,7 @@ $ socat tcp4-listen:10001,reuseaddr,fork exec:"env LD_PRELOAD=./libc.so_1 ./free ``` -## 题目逆向 +## 题目解析 我们先来看一下 main 函数: ``` [0x00400770]> pdf @ main @@ -702,7 +702,7 @@ Delete 的实现如下: 该函数在读入要删除的笔记序号后,首先将 Notes 结构体成员 `length -1`,然后将对应的 Note 结构体的 `isValid` 和 `length` 修改为 `0`,然后 free 掉笔记的内容(`*content`)。 -## Exploit +## 漏洞利用 在上面逆向的过程中我们发现,程序存在 double free 漏洞。在 Delete 的时候,只是设置了 `isValid =0` 作为标记,而没有将该笔记从 Notes 中移除,也没有将 `content` 设置为 NULL,然后就调用了 free 函数。整个过程没有对 `isValid` 是否已经为 `0` 做任何检查。于是我们可以对同一个笔记 Delete 两次,造成 double free,修改 GOT 表,改变程序的执行流。 #### 泄漏地址 @@ -1040,6 +1040,7 @@ $ whoami firmy ``` +#### exploit 完整的 exp 如下: ```python from pwn import * diff --git a/doc/6.1.8_pwn_dctf2017_flex.md b/doc/6.1.8_pwn_dctf2017_flex.md index 3f44189..8c7521d 100644 --- a/doc/6.1.8_pwn_dctf2017_flex.md +++ b/doc/6.1.8_pwn_dctf2017_flex.md @@ -3,6 +3,7 @@ - [题目复现](#题目复现) - [C++ 异常处理机制](#C-异常处理机制) - [题目解析](#题目解析) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -360,6 +361,8 @@ $ ldd flex 分析完了,接下来就写 exp 吧。 + +## 漏洞利用 #### stack pivot 在 `0x004012b4` 下断点,以检查溢出点: ``` @@ -465,7 +468,7 @@ $ whoami firmy ``` -#### Exploit +#### exploit 完整的 exp 如下: ```python from pwn import * diff --git a/doc/6.1.9_pwn_rhme3_exploitation.md b/doc/6.1.9_pwn_rhme3_exploitation.md index 2a6776d..cafb736 100644 --- a/doc/6.1.9_pwn_rhme3_exploitation.md +++ b/doc/6.1.9_pwn_rhme3_exploitation.md @@ -2,6 +2,7 @@ - [题目复现](#题目复现) - [题目解析](#题目解析) +- [漏洞利用](#漏洞利用) - [参考资料](#参考资料) @@ -630,6 +631,8 @@ She's gone! ``` 很好地验证了球员分配和删除的过程。 + +## 漏洞利用 #### alloc and select 然后是内存,根据我们对堆管理机制的理解,这里选择使用 small chunk(球员 name chunk): ```python @@ -883,7 +886,7 @@ $ whoami firmy ``` -#### Exploit +#### exploit 完整的 exp 如下: ```python from pwn import *