点击上方“凌天实验室”可订阅哦!
上篇穿越捷径:
这是《Java Web安全-代码审计》春节前最后一讲
通常我喜欢把代码审计的方向分为业务层安全
问题、代码实现
和服务架构
安全问题,。
1. 业务层安全常见问题
业务层的安全问题集中在业务逻辑
和越权
问题上,我们在代码审计的过程中尽可能的去理解系统的业务流程以便于发现隐藏在业务中的安全问题。
用户登陆、用户注册、找回密码等功能中密码信息未采用加密算法。
用户登陆、用户注册、找回密码等功能中未采用验证码
或验证码未做安全刷新
(未刷新Session中验证码的值)导致的撞库、密码爆破漏洞。
找回密码逻辑问题(如:可直接跳过验证逻辑直接发包修改)。
手机、邮箱验证、找回密码等涉及到动态验证码等功能未限制验证码失败次数
、验证码有效期
、验证码长度过短
导致的验证码爆破问题。
充值、付款等功能调用了第三方支付系统未正确校验接口(如:1分钱买IPhone X)。
后端采用了ORM框架
更新操作时因处理不当导致可以更新用户表任意字段(如:用户注册、用户个人资料修改时可以直接创建管理员账号
或其他越权修改操作)。
后端采用了ORM框架
查询数据时因处理不当导致可以接收任何参数导致的越权查询、敏感信息查询等安全问题。
用户中心转账、修改个人资料、密码、退出登陆等功能未采用验证码或Token机制导致存在CSRF漏洞。
后端服务过于信任前端,重要的参数和业务逻辑只做了前端验证(如:文件上传功能的文件类型只在JS中验证、后端不从Session中获取用户ID、用户名而是直接接收客户端请求的参数导致的越权问题)。
用户身份信息认证逻辑问题(如:后台系统自动登陆时直接读取Cookie中的用户名、用户权限不做验证)。
重要接口采用ID自增、ID可预测并且云端未验证参数有效性导致的越权访问、信息泄漏问题(如:任意用户订单越权访问)。
条件竞争问题,某些关键业务(如:用户转账)不支持并发、分布式部署时不支持锁的操作等。
重要接口未限制请求频率,导致短信、邮件、电话、私信等信息轰炸。
敏感信息未保护,如Cookie中直接存储用户密码等重要信息。
弱加密算法、弱密钥,如勿把Base64当成数据加密方式、重要算法密钥采用弱口令如123456
。
后端无异常处理机制、未自定义50X错误页面,服务器异常导致敏感信息泄漏(如:数据库信息、网站绝对路径等)。
使用DWR框架开发时前后端不分漏洞(如:DWR直接调用数据库信息把用户登陆逻辑直接放到了前端来做)。
2. 代码实现常见问题
代码审计的核心是寻找代码中程序实现的安全问题,通常我们会把代码审计的重心放在SQL注入、文件上传、命令执行、任意文件读写等直接威胁到服务器安全的漏洞上,因为这一类的漏洞杀伤力极大也是最为致命的。
###2.1 代码实现中常见的安全问题Checklist
任意文件读写
(文件上传、文件下载)、文件遍历
、文件删除
、文件重命名
等漏洞
SQL注入漏洞
XXE(XML实体注入攻击)
表达式执行(SpEL、OGNL、MVEL2、EL等)
系统命令执行漏洞(ProcessBuilder)
反序列化攻击(ObjectInputStream、JSON、XML等)
Java反射攻击
SSRF攻击
空字节截断漏洞漏洞在诸多编程语言中都存在,究其根本是Java在调用文件系统(C实现)读写文件时导致的漏洞,并不是Java本身的安全问题。不过好在高版本的JDK在处理文件时已经把空字节文件名进行了安全检测处理。
2013年9月10日发布的Java SE 7 Update 40
修复了空字节截断这个历史遗留问题。此次更新在java.io.File
类中添加了一个isInvalid方法,专门检测文件名中是否包含了空字节。
修复的JDK版本所有跟文件名相关的操作都调用了isInvalid
方法检测,防止空字节截断。
修复前(Java SE 7 Update 25
)和修复后(Java SE 7 Update 40
)的对比会发现Java SE 7 Update 25
中的java.io.File
类中并未添加\u0000
的检测。
受空字节截断影响的JDK版本范围:JDK<1.7.40
,单是JDK7于2011年07月28日发布至2013年09月10日发表Java SE 7 Update 40
这两年多期间受影响的就有16个版本,值得注意的是JDK1.6虽然JDK7修复之后发布了数十个版本,但是并没有任何一个版本修复过这个问题,而JDK8发布时间在JDK7修复以后所以并不受此漏洞影响。
参考:
JDK-8014846 : File and other classes in java.io do not handle embedded nulls properly。
维基百科-Java版本歷史
Oracle Java 历史版本下载
2.1.2 测试Java写文件截断测试
测试类FileNullBytes.java
:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author yz
*/
public class FileNullBytes {
public static void main(String[] args) {
try {
String fileName = "/tmp/null-bytes.txt\u0000.jpg";
FileOutputStream fos = new FileOutputStream(new File(fileName));
fos.write("Test".getBytes());
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用JDK1.7.0.25
测试成功截断文件名:
使用JDK1.7.0.80
测试写文件截断时抛出java.io.FileNotFoundException: Invalid file path
异常:
空字节截断利用场景
Java空字节截断利用场景最常见的利用场景就是文件上传
时后端使用了endWith
、正则使用如:.(jpg|png|gif)$
验证文件名后缀且文件名最终原样保存,同理文件删除(delete
)、获取文件路径(getCanonicalPath
)、创建文件(createNewFile
)、文件重命名(renameTo
)等方法也可适用。
空字节截断修复方案
最简单直接的方式就是升级JDK,如果担心升级JDK出现兼容性问题可在文件操作时检测下文件名中是否包含空字节,如JDK的修复方式:fileName.indexOf('\u0000')
即可。
任意文件读取漏洞即因为没有验证请求的资源文件是否合法导致的,此类漏洞在Java中有着较高的几率出现,任意文件读取漏洞看似很简单,但是在这个问题上翻车的有不乏一些知名的中间件:Weblogic
、Tomcat
、Resin
又或者是主流MVC框架:Spring MVC
、Struts2
。所以在审计文件读取功能的时候要非常仔细,或许很容易就会有意想不到的收获!
任意文件读取示例代码file-read.jsp
:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.io.ByteArrayOutputStream" %>
<%@ page import="java.io.File" %>
<%@ page import="java.io.FileInputStream" %>
<%
File file = new File(request.getParameter("path"));
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int a = -1;
while ((a = fis.read(b)) != -1) {
baos.write(b, 0, a);
}
out.write("<pre>" + new String(baos.toByteArray()) + "</pre>");
fis.close();
%>
访问file-read.jsp
文件即可读取任意文件:http://localhost:8080/file/file-read.jsp?path=/etc/passwd
快速发现这类漏洞得方式其实也是非常简单的,在IDEA中的项目中重点搜下如下文件读取的类。
JDK原始的java.io.FileInputStream
类
JDK原始的java.io.RandomAccessFile
类
Apache Commons IO提供的org.apache.commons.io.FileUtils
类
JDK1.7新增的基于NIO非阻塞异步读取文件的java.nio.channels.AsynchronousFileChannel
类。
JDK1.7新增的基于NIO读取文件的java.nio.file.Files
类。常用方法如:Files.readAllBytes
、Files.readAllLines
如果仍没有什么发现可以搜索一下FileUtil很有可能用户会封装文件操作的工具类。
Web Service
是一种基于SOAP协议
实现的跨语言Web服务调用,在Java中Web Service
有如下技术实现:Oracle JWS
、Apache Axis1、2
、XFire
、Apache CXF
、JBossWS
。
web.xml
配置Axis1.4
配置server-config.wsdd
文件注册Web Service
服务类和方法:
FileService
类,提供了文件读写接口:
使用IDEA创建Web Service
项目默认会创建管理Web Service
的API:/servlet/AxisServlet
、/services
、SOAPMonitor
、/servlet/AdminServlet
,*.jws
以及用监控Web Service
的端口5001
或5101
。
访问Web Service
的FileService
服务加上?wsdl
参数可以看到FileService
提供的服务方法和具体的参数信息。
使用SOAP-UI调用Web Service
接口示例:
需要注意的是Web Service
也是可以设置授权认证的,如实现了WS-Security
的WSS4J
。
使用IDEA根据wsdl生成Web Service
客户端代码:
设置wsdl地址、包名:
新建FileServiceTest
类测试接口调用:
package org.javaweb.codereview.axis.client;
import java.net.URL;
/**
* 文件Web Service服务测试
*
* @author yz
*/
public class FileServiceTest {
public static void main(String[] args) {
try {
FileServiceService fileService = new FileServiceServiceLocator();
URL webServiceUrl = new URL("http://localhost:8080/services/FileService");
FileServiceSoapBindingStub soapService = new FileServiceSoapBindingStub(webServiceUrl, fileService);
String content = soapService.readFile("/etc/passwd");
System.out.println(content);
} catch (Exception e) {
e.printStackTrace();
}
}
}
微信扫一扫
关注该公众号