OGeekCTF 2019 部分 writeups
TOC
- 1. PWN - babyrop
- 2. PWN - book manager
- 3. PWN - hub
- 4. PWN - 0 day manager
- 5. RE - babyre
- 6. Mobile - mblockchain
相关附件下载:ogeekctf2019.zip 。
PWN - babyrop
签到题。
靶机环境是32位的glibc-2.23。
int __cdecl check(int random) |
由于check
使用的是read
函数,则我们可以直接输入\0
开头的字符串来进行绕过,然后strlen
的长度就为0,则后面的strncmp
判断必定成功。
void __cdecl vul(char a1) |
之后的漏洞函数中,a1
是我们之前输入的第八个字符,如果我们输入\xff
时,则在read
时a1
会进行符号填充,那么我们就可以读入4294967295
(-1
)个字节,这将直接导致栈溢出,之后就行常规的ROP
。
脚本:
#!/usr/bin/python2 |
PWN - book manager
第二道签到题,靶机环境是glibc-2.23。
内置一大堆漏洞,这里我用最简单的heap overflow
。
在Add_text
功能中,size的大小是由用户决定的。
v6 = get_int(); |
但是在Update
功能中,其输入的大小指定为255
,直接导致heap overflow
。
printf("\nNew Text:"); |
而且由于Text
结构的输入没有null截断
,我们可以直接泄露libc地址
。
思路:
- 泄露libc地址
Add_chapter('aaaa\n') |
- 劫持
Text
结构体
因为劫持Text
结构体更简单,而且可以实现任意地址读写,我们只需要提前布置好heap
结构就行。
Add_section('aaaa\n', 'dddd\n') |
- 劫持hook
Update('dddd\n', p64(libc_addr + libc.symbols['system'])) |
脚本:
#!/usr/bin/python2 |
PWN - hub
靶机环境是glibc-2.27。
要是能开启PIE
并且使用glibc-2.23.so
的话,相信能成为更优质的挑战。
溢出点
程序流还是非常清晰明了的。
__int64 __fastcall main_function(char *a1) |
在Free
功能中,虽然将malloc_ptr
置为0,但是并没有将ptr_array
置为0,则我们可以直接输入index
为0,这样会直接导致double free
。
思路
- 修改stdout结构体为了泄露地址信息
一般在有PIE
的情况下,我们需要利用chunk残余的fd和bk
来对stdout的地址
进行爆破,但是这里没有PIE
,而且stdout的地址
就在bss段
上,我们可以直接利用tcache attack
进行控制。然后修改stdout->_flags
。
Malloc(0x18) |
奈何一次只能写入8 byte
,而且修改stdout地址的话,调用printf
函数时会发生阻塞现象,所以我们只能爆破对程序基本没有影响的stderr的地址
了,下面的代码功能就是爆破bss段
的stderr的地址
的低二位字节,使其指向stdout->_IO_write_base
的地址,这里是1/16
的几率。
Malloc(0x28) |
之后将地址指向我们要泄露的信息,通过调试可得:
pwndbg> p stdout->_IO_write_base |
在stdout->_IO_write_base
地址的低位字节为0xc8
的时候,可以泄露_IO_2_1_stdin_
的地址,所以对于的修改脚本如下:
Malloc(0x38) |
- 劫持hook
直接用tcache
的double free
即可。
Malloc(0x48) |
脚本
几率为1/16
。
#!/usr/bin/python2 |
PWN - 0 day manager
靶机环境是glibc-2.27。
其实漏洞非常简单,只不过其中大量的结构体一开始就吓跑了很多人,刚开始看到这么复杂的结构体我自己也吓了一跳,但是随着仔细的分析,程序慢慢变得简单。
下面是程序要用到的结构体:
typedef struct Link{ |
溢出点
这是我乱打payload
无意间发现的,下面是我的payload:
1 |
分析了Handle
功能之后,发现其三个结构都有一个致命的UAF
漏洞。
在Handle
功能中,处理的数目是由用户来确定的,但是当number
为0时,悲剧就发生了。
printf("How many you want to handle in?"); |
这里我举Logic
为例,也就是type为2时,在Handle
功能中,当number
为0时,则下面的代码会直接跳过,这里原本是由v17
来刷新this_control->con->array[2]
结构的指针,number
为0时,就什么也不做了,直接跳出,造成了UAF
。
v17 = this_control->con->array[2]; |
思路
由于源程序代码复杂功能简单,所以脚本我也就写的简单一点。
- 利用
UAF
漏洞,泄露 unsorted bin 的信息,从而计算libc地址
_sendline('1') |
调试结果如下:
pwndbg> pr |
- 绕过
tcache
由于使用的calloc
函数,它不会从tcache
里面拿chunk
,所以我们必须要先绕过tcache
,方法也很简单,就是不停的free
就行。
_sendline('1') |
调试结果如下:
pwndbg> bin |
可以看到fastbin
已经double free
了。
- 劫持hook
这里需要进行利用realloc
来进行栈调整,才能执行one gadget
。
_sendline('1') |
脚本
#!/usr/bin/python2 |
RE - babyre
题目给了一个压缩程序,但是没有相对应的解压程序,还给了一个压缩过的文件,要求我们根据分析压缩程序的算法写出相对应的解压程序即可。
根据IDA还原的算法源码:
// gcc -s -O3 compress.c -o compress |
通过下面测试,已经和原先的程序行为基本一致:
ex@Ex:~/ogeek2019/re/babyre$ ./compress in out |
分析代码可得,这是一个根据重复字符来压缩的算法,但是其长度和举例都是有限的,其长度是17,也就是byte_202040
的长度,而最大距离则正好是buf
的0x1000
。
if (number > v7) |
buf为该压缩算法的缓冲区,大小为0x1000
,其压缩的目的也主要取决于该缓冲区。
这是一个按位压缩的算法,从compress
函数的上面代码可知,该协议分为标志位和携带内容,当标志为1时,其协议长度分为9 bit
, 第一个bit为标志位,后面八个bit
为一个字符。
当标志为0时,其协议长度分为17 bit
, 第一个bit为标志位,然后12个bit
为buf缓冲区的地址,然后4个bit
为重复的次数,在解压的时候直接将其复制过来就行,这里主要是压缩重复的字节流。
只要知道压缩原理之后,只要按照其协议解压即可。下面是我写的解压程序:
// gcc -s -O3 uncompress.c -o uncompress |
之后用该程序进行解压,可以获得一张图片,flag就在图片里。
ex@Ex:~/ogeek2019/re/babyre$ ./uncompress output.file result |
Mobile - mblockchain
附件是一个安装包,对安装包就行解压,反汇编,得到下面主要代码:
// |
s
和s2
为我们的输入。
有下面这句话看出,hash时,只取 3个byte
,所以我们对这 3个byte
进行反向爆破,最终将在爆破出的结果中找到flag。
byte[] array = hash(new byte[] { hash[0], hash[hash.length / 2], |
下面是我写的爆破代码:
import java.security.MessageDigest; |
最终,将在结果中找到flag。