Go是一种静态强类型、编译型语言。Go 语言语法与 C相近。( Go 语言的作者之一 Ken Thompson 也是 C 语言的作者。)
go默认情况下panic⾮常多,不适合利⽤,于是本题使⽤unsafe包构造出⽐较容易利⽤的栈溢出。
unsafe包主要是提供了功能比较强的指针,所以这题倒也不是没有实际意义。
逆向分析
Go编写的,去符号表。其实我赶紧能不能F5都一样,F5了之后可读性也一般。
IDA7.5的话用 IDAGolangHelper 可以根据pclntab恢复符号表(其实第一天我卡这里挺久的,如果一开始就用的是IDA7.6说不定就出了)。IDA7.6则是自己就能恢复的差不多。原理大概都是pclntab。多亏了用的IDA7.5,了解到了这个原理,在分析的时候才能想到也许这个结构体被篡改过。
调试过程中发现下在main.main的断点不会停,刚开始怀疑是多线程的原因,后来跟进去看,发现程序是正常执行的,再根据gdb里的地址去IDA看,发现运行的代码是math.init,于是转向分析math.init。动态调试的可信度远大于静态分析。
这题最有意思的点就在于此,这个main.main做的很真,要不是我程序里没有他打印的字符串的话我很难起疑心。
math.init里,判断数字的地方不再只有0x12345678一种分支,还多了另外两种,第二种只是重来一次,重点分析第三种。
crushBullsCows
这里是一个BULLS AND COWS游戏,理论上7次之内必定能获胜。但当时就剩两小时了,过了这边调漏洞都要半天,肯定没时间自己设计了(其实就是又懒又菜,不想动脑子写)于是找到了 Mastermind 这个仓库,里面提供了一种平均5次就能获胜的算法,缺点是时间复杂度很高,跑起来很慢,好在这题没有alarm,无伤大雅。优点是这个作者写的文档和注释相当详细,读一遍就能开始魔改了。
认识的一个师傅是直接手动玩游戏过的,挺实际的解决办法,可惜我不会玩。
栈溢出
虽然创建了0x800的slice,但是bufio.Reader.read是先读到栈上的,经调试,存在栈溢出。能想到的打法就是ROP了。当时参考的是这道题 挖宝题目设计思路
但是我当时找不到合适的gadget,在找能够控制rdi的寄存器的gadget时就卡住了(汇编能力不足)
后来看了那个师傅的WP,发现这些人家的汇编水平确实吊打我。
exp
1 | from pwn import * |
总结
- 遇到困难不要睡大觉,我要是以前碰到这种题肯定直接睡大觉了,但事实证明,静下心来分析题目,多搜索搜索总能有些头绪的。
- 多调调,静态分析看起来很安全的程序也可能存在漏洞
- 汇编能力可能还要再强一点(但也不一定,谁没事一直玩gadget,够用就行
- IDA对于C语言之外的语言支持都有待提高
- 百度就是一坨屎,做题的时候一定要用谷歌