SCTF2021 dataleak
Keyword: cJSON, CVE-2019-11834
题目描述
Never trust c pointer magic and escape characters,
题目分值:281
解题人数:52
逆向分析
逻辑还是比较简单的,读取两个buf,然后调用cJSON_Minity
对buf1进行处理,接着把buf2打印出来。明显,在远程环境下buf2后面的就是flag,我们想要把它读取出来。
此时的内存如下
1 | +--------------------------+---+ |
明显程序本身不存在漏洞可以利用,漏洞只能是出在cJSON_Minity
里。 cJSON_Minify
移除了 JSON 或者 JSON+C(JSON+C = JSON with comments) 文档中的所有空白和注释。网上搜一下这个函数就能看到cross border read&write。
can bypass ‘\x00’,bug can be trigger with json string buffer that end with ‘\x00’ or not
这里有两个0需要跳过,我们在libcjson.so
里可以看见
简单来说,凡是/*??...??\x00?
的字符串都会被删去(只要?不为*或/或\x00)
当buf1以/*
结尾时,执行了两次++arg
,此时*arg = 0
,退出了while循环,然后arg+=2
。那么我们末尾的两个0就被跳过了。它就会接着对buf2进行处理,如果对buf2故技重施,那最后buf1,buf2,flag就会结合为一个字符串。
动态调试
调用cJSON_Minity
之后的栈如下
可以看到\x00
都被去掉了,但是flag长度是22而这里的输出用的是write()且限制了11的长度没法一次就打出来
我们有两次输入buf1&2的机会,设计好payload就可以达到目的。
已知/*
之后的内容(直到\x00
)都会被删掉,我们可以通过这个来将flag分两次打出来
第一次:让flag正好到buf2的地址,那我们构造如下
1 | +--------------------------+---+ |
1 | buf1 = 'a'*14 + '/*' |
第二次:
1 | +--------------------------+---+ |
1 | buf1 = ('a' + '/*').ljust(14,'a') |