JSP上传漏洞
一、上传漏洞成因
文件上传过程中,通常因为未校验上传文件后缀类型,导致用户可上传jsp等一些webshell文件。代码审计时可重点关注对上传文件类型是否有足够安全的校验,以及是否限制文件大小等。
解决的方法:主要是限制文件的后缀名的校验,还有限制文件的大小
文件上传漏洞的攻击与防御方式
https://www.jianshu.com/p/5ebba0482980
1.前端限制(文件类型的验证)
主要是前端的文件名的检查
这个一般很好的绕过
1.burp suite 绕过,抓包后面再修改文件的类型的后缀名
2.或者是禁用js 用hackbar 火狐的noscript 来绕过前端的验证
2.检查扩展名
用黑白名单的方式来限制文件的扩展名(后台的验证是合法还是不合法)
A>黑名单策略,文件扩展名在黑名单中都是不合法的,主要出现黑名单里面的类型,就不会允许
B>白名单的策略,文件的名字扩展名不在名单中就是不合法的
白名单的策略更加的安全一些,只允许我们接受的文件的扩展名,黑名单可能收集的不全面,可能出现隐患
绕过方法
在一些Web server中,存在解析漏洞
1.老版本的IIS6中的目录解析漏洞,如果网站目录中有一个 /.asp/目录,那么此目录下面的一切内容都会被当作asp脚本来解析
2.老板本的IIS6中的分号漏洞:IIS在解析文件名的时候可能将分号后面的内容丢弃,那么我们可以在上传的时候给后面加入分号内容来避免黑名单过滤,如 a.asp;jpg
3.旧版Windows Server中存在空格和dot漏洞类似于 a.php. 和 a.php[空格] 这样的文件名存储后会被windows去掉点和空格,从而使得加上这两个东西可以突破过滤,成功上传,并且被当作php代码来执行
4.nginx(0.5.x, 0.6.x, 0.7 <= 0.7.65, 0.8 <= 0.8.37)空字节漏洞 xxx.jpg%00.php 这样的文件名会被解析为php代码运行(fastcgi会把这个文件当php看,不受空字节影响,但是检查文件后缀的那个功能会把空字节后面的东西抛弃,所以识别为jpg)
5.apache1.x,2.x的解析漏洞,上传如a.php.rar a.php.gif 类型的文件名,可以避免对于php文件的过滤机制,但是由于apache在解析文件名的时候是从右向左读,如果遇到不能识别的扩展名则跳过,rar等扩展名是apache不能识别的,因此就会直接将类型识别为php,从而达到了注入php代码的目的
3.检查http header 中的centent-type
原理
HTTP协议规定了上传资源的时候在Header中加上一项文件的MIMETYPE,来识别文件类型,这个动作是由浏览器完成的,服务端可以检查此类型不过这仍然是不安全的,因为HTTP header可以被发出者或者中间人任意的修改,不过加上一层防护也是可以有一定效果的
绕过方法
使用各种各样的工具(如burpsuite)强行篡改Header就可以,将Content-Type: application/php改为其他web程序允许的类型
Content-Type: image/jpg
Content-Type: image/png
Content-Type: text/plain。
常用的MIMETYPE表
4.分析文件头内容来检查文件类型
在正常情况下,通过判断前10个字节,基本上就能判断出一个文件的真实类型。
可以通过比如php的exif_imagetype()函数,一个通过这种方法来过滤的示例代码如下:
绕过方法
给上传脚本加上相应的换数头字节就可以,php引擎会将 <?之前的内容当作html文本,不解释而跳过之,后面的代码仍然能够得到执行比如下面:
(一般不限制图片文件格式的时候使用GIF的头比较方便,因为全都是文本可打印字符。)
5.限制Web Server对于特定类型文件的行为
导致文件上传漏洞的根本原因在于服务把用户上传的本应是数据的内容当作了代码,一般来说,用户上传的内容都会被存储到特定的一个文件夹下,比如我们很多人习惯于放在 ./upload/ 下面要防止数据被当作代码执行,我们可以限制web server对于特定文件夹的行为。
因此可以使用服务器程序的接口来进行限制
以Apache为例,我们可以利用 .htaccess 文件机制来对web server行为进行限制
禁止脚本执行有多种方式可以实现,而且分别有不同的效果:
1.指定特定扩展名的文件的处理方式,原理是指定Response的Content-Type可以加上如下几行
AddType text/plain .pl .py .php
这种情况下,以上几种脚本文件会被当作纯文本来显示出来,你也可以换成其他的Content-Type
2.如果要完全禁止特定扩展名的文件被访问,用下面的几行
在这种情况下,以上几种类型的文件被访问的时候,会返回403 Forbidden的错误
3.也可以强制web服务器对于特定文件类型的处理,与第一条不同的是, 下面的方法直接强行让apache将文件识别为你指定的类型,而第一种是让浏览器
符合上面正则的全部被认为是纯文本,也可以继续往里面加入其他类型。
4.只允许访问特定类型的文件
在一个上传图片的文件夹下面,就可以加上这段代码,使得该文件夹里面只有图片扩展名的文件才可以被访问,其他类型都是拒绝访问。
这又是一个白名单的处理方案,永远记得,白名单是最有保障的安全措施
绕过方法
可以通过 move_uploaded_file 函数把自己写的.htaccess 文件上传,覆盖掉服务器上的文件,来定义文件类型和执行权限如果做到了这一点,将获得相当大的权限。
6.文件系统00截断
原理
在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束。利用00截断就是利用程序员在写程序时对文件的上传路径过滤不严格,产生0x00上传截断漏洞。
绕过方法
通过抓包截断将【evil.php.jpg】后面的一个【.】换成【0x00】。在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束,从而将【evil.php.jpg】的内容写入到【evil.php】中,从而达到攻击的目的。
二、实例子操作
文件上传模块
选择shell的木马
上传的木马解析图片
访问图片地址:http://localhost:8080/WebGoat/uploads/shell.jsp
登陆查看
获取到系统的webshell
shell配备相关的操作工具
查看系统源码:
在源码中找到对应的文件传入的地方
主要是对上传的文件没有过滤:
1、 如何防护,过滤扩展名
源代码
String uploaded_file_path = uploads_and_target_parent_directory
+ UPLOADS_RELATIVE_PATH
+ java.io.File.separator
+ item.getName();
File uploadedFile = new File(uploaded_file_path);
item.write(uploadedFile);
System.out.println("Stored file:\n" + uploaded_file_path );
// add url to database table
Connection connection = DatabaseUtilities.getConnection(s);
Statement statement = connection.createStatement();
// attempt an update
String updateData1 = "UPDATE mfe_images SET image_relative_url='" + UPLOADS_RELATIVE_PATH + "/"
+ item.getName() + "' WHERE user_name = '"
+ s.getUserName() + "';";
---------------------------------------------------------------------------------------------
修改的添加对文件名后缀的白名单
String uploaded_file_path = uploads_and_target_parent_directory
+ UPLOADS_RELATIVE_PATH
+ java.io.File.separator
+ item.getName();
String lower_file_name = item.getName().toLowerCase();//先将获取的文件名转换为小写
//白名单的控制允许的文件
if(lower_file_name.endsWith(".jpg") ||
lower_file_name.endsWith(".gif") ||
lower_file_name.endsWith(".png") ||
lower_file_name.endsWith(".bmp"){
File uploadedFile = new File(uploaded_file_path);
item.write(uploadedFile);
System.out.println("Stored file:\n" + uploaded_file_path );
}
// add url to database table
Connection connection = DatabaseUtilities.getConnection(s);
Statement statement = connection.createStatement();
// attempt an update
String updateData1 = "UPDATE mfe_images SET image_relative_url='" + UPLOADS_RELATIVE_PATH + "/"
+ item.getName() + "' WHERE user_name = '"
+ s.getUserName() + "';";
2、取消上传目录脚本执行权限
catalina.policy文件(设置目录访问权限)
三、防护总结:
1、前端限制
2、上传的黑、白名单限制(文件的大小、文件后缀名、文件头)
3、通过tomcat的上传管理机制
4、现在上传目录的解析权限
5、租用OSS云存储空间,将文件和网址分离
四、学习了解
相关文章:
https://www.cnblogs.com/yuxiaole/p/9293472.html
https://blog.csdn.net/tanzhen1991910/article/details/53260446
公众号:
thelostworld:
个人知乎:https://www.zhihu.com/people/fu-wei-43-69/columns
个人简书:https://www.jianshu.com/u/bf0e38a8d400