唉,今天复现了一天DDCTF的mysql弱口令都没成功,云服务器重装了三次,才装好了mysql,然后按照题目步骤一步步来,我发现要同时开启两个py文件,但是我的云服务器只能开一个终端啊,唉,之前的找到一个实验的环境想尝试这个漏洞,结果也加载不出来,真是太不顺了,这次国赛的题,我发现其实还是自己知识面太窄了,所以很多地方没有思考到,其实题目也不是特别难吧。
第一道题justsoso虽然只是签到题,但是因为知识面的不足,所以导致有几个地方没有绕过,其实在比赛的时候去查一下的parse_url的漏洞,说不定可以做出来。其实题目本身很简洁,就是一个反序列化。
题目里设定了两个类,Handle和Flag,其中Handle类里有魔术方法__wakeup(),在类的实例化对象反序列化时就会调用,会将所有的变量值设为null,这个之前做过题目了,只要设置构造的序列化对象的属性比真实属性值高,就可以不执行这个函数。
再看Flag类里有一个魔术方法__construct()会在实例化对象时执行,将token_flag,token赋值一个随机的md5值。然后在getFlag函数里,首先会给token_flag重新赋值,再判断token_flag和token是否相等,如果不作任何处理的话,这个条件肯定是无法满足的,但是看了wp以后,学到了一个姿势,在这个__construct函数中添加一个 $token=&$token_flag,令 $token=$token_flag的引用,这样设置会令 $token和$token_flag指向同一个内容,不管其中的哪个变量的值变了,另一个都会跟着改变。
这里注意到Handle的属性是私有属性,我们在构造这个类的序列化对象时,它会自动赋值
但其实字符串里的内容为%00Handle%00handle ,这里我们在传入的时候需要自己添加上去。
最后就是我们在Flag里设置的file属性了,因为在代码里会过滤flag字样
但是问题出在这个parse_url,这个函数先提取我们传入的uri,然后把接收的值分类放入数组,然后parse_str提取query中的值,也就是?号的值(参数),可是我们可以在uri的开头多加几个斜杠/,这样会导致parse_url函数解析错误,使原本应该被传入query键值中的参数,被认为是path的键值,就可以绕过这个判断条件了。
所以最后的payload应该为payload=O:6:"Handle":2:{s:14:"%00Handle%00handle";O:4:"Flag":3:{s:4:"file";s:8:"flag.php";s:10:"token_flag";N;s:5:"token";R:4;}}
2、lovemath
由于题目环境已经关闭了,但是当时这道题也算有一点思路,想到要用白名单中的数学函数来构造payload,但是一直没发现base_convert这个函数。
在本地复现的时候一开始无法执行命令,后来发现是php版本的问题,php5不能这样执行命令,php7可以。题目环境是linux系统,我的主机是windows系统,所以修改了一些命令。
base_convert可以将我们传入的十进制转换为三十六进制,三十六进制中包含了a-z,这样我们可以传入字母了,例如用
base_convert(55490343972,10,36)
再执行一下系统命令查看当前目录下的文件
system(dir)
但是如果要查看文件内容的话,我们就要使用到特殊字符了,比如构造一个_GET,虽然[]被过滤了,但是可以用另一种方法设置。构造下面的payload
$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pow}($$pi{abs})&pow=readfile&abs=flag.php
base_convert(37907361743,10,36) -----> hex2bin
dechex(1598506324)------->十六进制的 _GET
($$pi){pow}($$pi{abs}) 相当于 $_GET['pow']($_GET['abs'])
所以我构造了一个readfile(flag.php)