-
-
[原创]CTF2019_Q1_挖宝
-
发表于:
2019-3-25 13:24
8851
-
最近几天事情比较多,抽几天晚上看了一下,这题最后没有解决(虽然还剩一星期,不过想来下个星期更没时间了,应该不碰了),把踩坑过程写一下。
首先通过字符串判断是个go程序,使用golanghelper恢复符号表:
首先可以看到四个宝藏位置:(0,5),(5,0),(5,5),第4个没想到办法绕
当获得宝藏后会调用main_treasure:
即获取一次输入并copy到预先分配的一个位置,而这个位置分配的空间大小为0x30,因此这里存在溢出(具体go的内存分配机制可以在网上找到)
继续看可以发现main_scan内:
注意到一个Scanner结构体io_arg,动态调试看到其分配位置0xC820018080(在本地开启随机化调试也会一直是此地址,基本上go内部实现的栈空间地址不会改变,但是通过pwntools启动地址会不同(虽然也不改变),不太明白为什么),这个位置距离溢出位置0x00000C8200122D0不是太远,调试中可以看到能被覆盖,在go的源码中看到:
可以看到其包含了两个函数指针,在ida中也可以看到有两处可以利用函数指针劫持程序流(bufio__ptr_Scanner_Scan函数):
1:
2:
所以我们根据对应条件来覆盖函数指针并劫持程序流即可,不过很容易发现,一旦覆盖,原本应该调用os__ptr_File_Read来获取输入流,覆盖后就完全没有办法控制程序,所以这里需要保证可以直接获取shell,观察程序,看到了go内部实现的syscall_Syscall:
可以看到这里会根据栈中参数调用syscall
但是因为地址随机化,只能在go本身分配的栈中(地址确定)找是否含有此函数的指针,在0x00000C820000200处会一直存在syscall_Syscall+5
即:
不过最后我卡在了参数构造上,最接近的构造结果时syscall(0x3b,"/bin/sh",......,......),后面还需要两个参数(0,0),但是通过源码和静态汇编都可以看出没办法实现(源码详见/src/bufio/scan.go)(不排除有办法但是我审错了,但是实在没时间看了)
最后结果:
可以看到因为后面两个参数无法控制失败了,不过确实劫持了程序流到伪造的syscall_Syscall
虽然失败了,不过想来以后这个可能能用上,先记下来
实际上如果有leak,leak程序加载基址后完全可以伪造整个Scanner结构体造成任意地址写(buf可控),而栈地址已知,后面很简单就可以拿shell,或者leak libc后直接one_gadget来获得shell都可以,不过没想到leak方法才采取syscall方案,感觉预期解是利用go内存分配机制伪造span list指针啥的,不过没想到好的利用技巧,再加上时间上的不允许,只试验了这个方法,赛后来看夜影师傅的操作。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)