搭建漏洞服务
还是先搭一个漏洞的服务吧:新建一个~/Desktop/php/upload文件夹,文件夹下存在如下结构的文件和文件夹:
$ tree
.
├── files
└── upload.php
1 directory, 1 file
upload.php:
<html>
<body>
<form action="upload.php" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>
<?php
if ($_FILES["file"]["error"] > 0) {
echo "Error: " . $_FILES["file"]["error"] . "<br />";
}
else {
// 判断当期目录下的 upload 目录是否存在该文件
// 如果没有 upload 目录,你需要创建它,upload 目录权限为 777
if (file_exists("files/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " 文件已经存在。 ";
}
else
{
echo "PWD: " . `pwd` . "<br />";
echo "Upload: " . $_FILES["file"]["name"] . "<br />";
echo "Type: " . $_FILES["file"]["type"] . "<br />";
echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
// 如果 upload 目录不存在该文件则将文件上传到 upload 目录下
$file_path = "files/" . $_FILES["file"]["name"];
$success = move_uploaded_file($_FILES["file"]["tmp_name"], $file_path);
echo "Stored in: " .$file_path."<br/>";
if(file_exists($file_path)){
$str = file_get_contents($file_path);//将整个文件内容读入到一个字符串中
$str = str_replace("\r\n","<br />",$str);
$str = htmlspecialchars($str);
echo "File Contents: $str";
}
}
}
?>
配置nginx服务:
server {
listen 80;
listen [::]:80;
server_name test.com;
root /home/repersp/Desktop/php;
index test.php;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# With php7.0-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# With php7.0-fpm:
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
}
改完host之后网站正常访问,接着我们上传一句话,这里因为之前装了安全狗,我们用%00截断过一下狗:
文件上传好了,用一下看看:
可以看到,即使用了通用防护措施,但是若网站本身就是一个脆弱的,那么依旧有风险。
防护
我们知道,通过php判断后缀名,判断文件开头的几个字符是否为图片,判断Content-Type都是可以通过伪造绕过的,唯一的办法就是配置nginx,确保上传目录不被执行:
server {
listen 80;
listen [::]:80;
server_name test.com;
root /home/repersp/Desktop/php;
index test.php;
location ~ \/upload\/files\/.* {
root /home/repersp/Desktop/php;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# With php7.0-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# With php7.0-fpm:
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
}
可以看到这样做代码只是展现在前台而不会被执行
任意文件读取防御
如果网站需要用户上传zip压缩文件,并且展现了zip压缩的内容,那么用户可以上传一个压缩后的符号链接文件,这样php会打印被链接的文件内容,即任意文件读取,这时代码里面还需要判断zip压缩里的文件类型。
目录穿越防御
如果网站设计缺陷可以使用../
将文件上传到上层目录(当然这里不存在,因为表单默认过滤了../
及其前面的字符),并且用户可以控制目录的话,还需要在代码中检查文件名。