记录一下华为3场CTF的pwn题,题量都特别大,希望能尽量做吧,同时学到更多东西。
第一场
cpp
程序分析
c++写得,不是很复杂,算是C++中的简单题。
1 | if ( v11[0] != 1 ) |
漏洞很明显,在程序最后存在一个UAF输出函数可以供我们泄露地址,最后还存在一个读函数,可以让我们释放后修改堆内容。
虽然是 2.31的环境,但是影响不大。
利用分析
思路很常规,先通过tcache泄露堆地址。
然后先填充tcache_bin
的个数为7,劫持tache_struct_perthread
这个结构体,申请0x291
的堆块,释放到unsortedbin
来泄露地址。
最后tcache_poisoning
攻击劫持 free_hook
。
EXP
1 | from pwn import * |
game
这道题难点,在于如何进入read
的栈溢出,由于每次程序传输的表达式都是变化的,需要我们自动化的写一个能够进入read
函数的代码。那么很自然的想到符号执行的经典工具:angr
。这道题的 angr
代码是 逆向师傅给我们的,但是赛后我自己也学了一下angr
,可以参考我写的angr学习笔记
。这里就不放angr
代码了。
程序分析
1 | __int64 __fastcall sub_4006F9(int a1) |
如果就单静态程序分析来说,这里存在一个很明显的栈溢出,而且溢出长度很大。
利用分析
这道题,和前不久的蓝帽杯决赛的pwn3
很类似,都是明显的栈溢出。但是那道Pwn3
当时用的投机做法,直接用 高位地址做滑板指令修改 libc_start_main
地址为 gadget
地址。需要靠运气爆破,成功几率并不高。
这道题,当时xmzyshyphc
学长给我说了一个方法,即 修改 got
表里的一个函数地址为 syscall
地址。然后利用 libc_csu
和 syscall
来实现函数调用。
但这里,有几个小技巧:
如何选取syscall
地址:
- 建议选择函数内部调用了
syscall
的got
表地址,这样我们就只需要覆写最低位的一字节偏移或一位偏移,成功率极高。
1 | ► 0x7ffff7ad9280 <alarm> mov eax, 0x25 |
如上所示,alarm
函数 +5
处 即是一个 syscall
。那么我们选择将 alarm_got
的最低一字节改为 0x85
即可。
如何getshell
:
由于有了syscall
和 csu
,我们可以直接先考虑能不能找到一个 pop rax, ret
的 gadget
,这样我们后续就能够不用泄露libc
地址,直接调用 system
。但是没有合适的 pop rax, ret
。这里的技巧为,当我们使用 read
读取 /bin/sh
到 bss
段上时,我们可以在后面填充到 59
个字符,这样read
函数返回值为rax= 59
,这样我们如果接着执行 syscall
,那么就能够直接执行 execve
函数。
EXP
1 | from pwn import * |
第二场
honorbook
基于 riscv
架构的,IDA
不能反汇编,后面选择用 ghidra
,发现也反汇编不了。但是,官网现在最新版的ghidra
可以。一旦能够反汇编,这道题其实挺常规的。
程序分析
1 | void add(void) |
在 Add
函数中,在输入msg
时,存在一个 off-by-one
漏洞。
利用分析
这道题libc
是2.27的,那么就是一个简单的 tcache off-by-one
漏洞,但是唯一的难点就是这道题无法使用 pwndbg
等插件调试,对于看堆栈很不友好。
其次,就是其 libc
地址中,总是会有 ‘\x00’出现,也就是我们输出地址时,只能输出部分地址,需要我们每次一字节的输出。
这道题的堆环境如下:
1 | 0x31 |
我们通过 0xf1
的堆块,可以修改 0x31
的堆头。做法就是修改 0x31
为 0xf1
,然后将其放入 tcache
中,这样就可以绕过对于堆头size
的检查。
然后我们再申请两次,那么就能够实现我们伪造的 fake_chunk
能够覆写 下一块 0xf1
的堆块。
泄露地址时,每次覆盖一个字节,如果输出为 \n
,则说明其下字节为 \x00
。否则就能够输出其下一字节。
EXP
1 | # encoding=utf-8 |
第三场
HarmoShell
程序分析
1 | void echo(longlong param_1) |
echo
函数,最后读取用户输入时,存在栈溢出。
利用分析
由于是 riscv64
架构的,调试不了。但是感觉总体和 mips
的做法差不多。
可以找到 csu
地址,利用 csu
来布置 参数和执行函数。
泄露地址,则利用c++ 自己的标准输出函数来泄露地址。
EXP
1 | from pwn import * |
PWNI
程序分析
32位 Arm
的栈溢出,做法仍然是利用 csu
来布置参数和执行函数。
利用分析
1 | .text:00010540 CMP R9, R5 |
32位下的csu
如上所示,参数布置基本变化不大,不过这里是一个循环,我们不需要再自己调整返回值。
此外,我们必须保证 R5
为1,这样才不会跳出该循环。
EXP
1 | # encoding=utf-8 |
- 本文作者: A1ex
- 本文链接: http://yoursite.com/2020/12/25/2020华为CTF/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!