1. 前言
翻找以前的资料的时候,突然发现了好久前收集的一些Java代码审计的搜索思路和关键字,整理一下。
2. 常见漏洞
2.1 SQL注入
漏洞成因:
- 直接使用SQL语句拼接,将用户传入的参数通过字符串拼接的方式传入查询语句。
如: String sql = "select * from test where id = " + id;
- 预编译使用有误,没有调用set方法变量与占位符进行对应。
1 | 如: |
- 对
%
和_
没有进行显示处理,导致用户可以自行拼接进行模糊查询。 - 不能参数化的位置,还是有可能存在拼接的情况,如
order by
后面。
如: String sql = "select * from test where id = ? order by '" + time + "' asc";
Mybatis
中,#{}
是预编译处理,${}
是字符串替换,使用${}
就可能导致SQL注入。
如: Select * from news where title like '%#{title}%'
本质上来说,是将用户的输入当作代码执行,程序将用户的输入拼接到了SQL语句中,改变了原来SQL语句的语义造成的攻击。
常见样例:
DAO:存在拼接的SQL语句
1 | String sql="select * from user where id="+id |
Hibernate框架
1 | session.createQuery("from Book where title like '%" + userInput + "%' and published = true") |
Mybatis框架
1 | Select * from news where title like ‘%${title}%’ |
审计策略:
- 重点关注创建查询的函数如
createQuery()
、createSQLQuery()
、createNativeQuery()
。 - 定位SQL语句上下文,查看是否有参数直接拼接,是否有对模糊查询关键字的过滤。
- 是否使用预编译技术,预编译是否完整,关键函数定位
setObject()
、setInt()
、setString()
、setSQLXML()
关联上下文搜索set*
开头的函数。 Mybatis
中搜索${}
,因为对于like模糊查询、order by排序、范围查询in、动态表名/列名,没法使用预编译,只能拼接,所以还是需要手工防注入,此时可查看相关逻辑是否正确。- JPA搜索
JpaSort.unsafe()
,查看是否用实体之外的字段对查询结果排序,进行了SQL拼接。以及查看EntityManager
的使用,也可能存在拼接SQL的情况。
关键字:
1 | Statement |
2.2 XSS注入
漏洞成因:
网站与后端交互的输入输出没有做好过滤,导致攻击者可以插入恶意js语句进行攻击。根据后端代码不同,大致可以分为反射型、存储型、DOM型。
如:
1 | @RequestMapping("/xss") |
这里接收了用户输入的参数name,然后又直接输出到了页面,整个过程没有任何过滤。
常见样例:
存储型XSS,根据已知的用户ID查询用户的数据并显示在JSP页面上。如果存入的数据存在未经过滤的恶意js代码,就会造成xss攻击。
1 | <% ... |
审计策略:
审计过程要点还是定位用户的输入输出,也就是梳理数据交互以及前端展示的过程。找到一条完整的利用链之后,就是结合现有的安全措施(输出编码、过滤器)等进行判断,例如是否存在绕过的可能,或者是没有任何安全防护可直接造成攻击。
一般来说会使用全局的Filter进行xss的过滤,但通常可能存在漏网之鱼,所以也需要审计全局过滤规则是否完善。可以通过关键字XssFilter
进行搜索。
关键字:
1 | <%= |
2.3 XXE漏洞
漏洞成因:
XXE就是XML外部实体注入。当允许引用外部实体时,通过构造恶意内容,就可能导致任意文件读取、系统命令执行、内网端口探测、攻击内网网站等危害。
常见样例:
如:
1 |
|
使用不可信数据来构造XML会导致XML注入漏洞,如果用户允许输入结构化的XML片段,则他可以在XML的数据域中注入XML标签来改写目标XML文档的结构与内容。
Java中的XXE支持以下协议:http、https、file、ftp、mailto、jar、netdoc
,可以利用file协议读取文件,利用http协议探测内网,没有回显时可组合利用file协议和ftp协议来读取文件。如果存在报错的情况下还可以尝试使用报错XXE进行敏感信息的获取,甚至是尝试递归调用造成拒绝服务攻击。
审计策略:
XML解析设计的业务功能点:WebServices接口
、RESTful接口
、Excel文件解析
、Soap协议
等。
漏洞触发点就在XML解析时,因此重点审计XML解析器是否设置了相关的安全属性,禁用DTDs或者禁止使用外部实体,还有是否使用了不安全的漏洞组件等。
除此之外,关注StreamSource
、XMLConstants
、StringReader
等方法的调用,在项目中搜索.xsd
文件也是一种方法。
关键字:
部分解析器如下:
1 | javax.xml.parsers.DocumentBuilder |
2.4 SSRF漏洞
漏洞成因:
SSRF形成的原因大都是由于代码中提供了从其他服务器应用获取数据的功能,但没有对目标地址做过滤与限制。比如从执行URL链接获取图片、下载等。
同时Java中的SSRF利用方式比较局限,大致有两种:利用file协议任意文件读取
和利用http协议端口探测
。
常见样例:
SSRF支持的大概协议如下:
1 | file ftp mailto http https jar netdoc |
样例:
1 | String url = request.getParameter("url"); |
漏洞代码四种情况:
- Request
1 | Request.Get(url).execute() |
- openStream
1 | URL u; |
- HttpClient
1 | String url = "http://127.0.0.1"; |
- URLConnection和HttpURLConnection
1 | URLConnection urlConnection = url.openConnection(); |
审计策略:
只要是能够对外发起网络请求的地方,就有可能会出现SSRF漏洞。重点查找以下函数:
1 | HttpClient.execute |
new URL():
构造一个URL对象openConnection():
创建一个实例URLConnectiongetInputStream():
获取URL的字节流
关键字:
出现SSRF漏洞的主要业务有:
- 通过URL地址分享网页内容
- 在线服务
- 通过URL地址加载或下载图片
- 加载远端配置
因此,我们需要重点关注下HTTP协议连接,当然还有我们常用的Socket协议连接
HTTP请求操作函数
1 | om.alibaba.druid.util.HttpClientUtils |
Socket相关类
1 | AsynchronousServerSocketChannel.accept/bind |
2.5 任意文件操作类漏洞
漏洞成因:
常见的一些Java文件操作类的漏洞:任意文件读取、下载、删除、修改,这类漏洞的成因基本相同,都是因为程序没有对文件和目录的权限进行严格控制,或者说在校验不当的情况下,用户可以绕过限制对服务器上任意文件进行操作。
常见样例:
如任意文件读取:
1 | @GET |
1 | def getWordList(value:String) = Action { |
任意文件写入:
1 | file file = new File(getExternalFilesDir(TARGET_TYPE), filename); |
审计策略:
首先关注包含这些功能的类和函数:
1 | sun.nio.ch.FileChannelImpl |
在使用这些函数时,对于用户传递来的文件对象/文件名/文件路径,是否进行了正确的处理:
- 是否限制了可操作文件的路径、文件类型、文件所有者
- 是否将敏感文件进行排除
- 查找
getPath()
、getAbsolutePath()
,查看是否有错误的路径判断
再排查程序的安全策略配置文件,全局搜索permission
、Java.io.FilePermission
、grant
字样,查看是否只为程序的绝对路径赋予读写权限。
关键字:
1 | getPath |
2.6 命令执行漏洞
漏洞成因:
服务端没有针对执行命令的函数进行过滤,导致攻击者可以提交恶意构造语句。Java中常见如:Runtime.exec() Process ProcessBuilder.start
常见样例:
Java中的命令执行离不开调用反射的机制,在实际的场景往往离不开反序列化的利用。
1 | import java.io.*; |
上面的代码利用Runtime.exec()
方法调用dir
命令。
攻击者可以利用&
符号执行多条命令,如:
1 | java -Ddir="..\\ & whoami" |
审计策略:
RCE出现的场景很多,需要分类具体分析,大致可归类为下面几种
1 | 服务端直接存在可执行函数(exec()等),且对传入的参数过滤不严格导致 RCE 漏洞 |
关键字:
审计时可以重点关注下能执行命令的一些功能和函数:
1 | Runtime.getRuntime().exec() |
2.7 反序列化漏洞
漏洞成因:
- Java程序使用
ObjectInputStream
对象的readObject()
方法将反序列化数据转换为Java对象。如果被反序列化的对象重写了readObject()
方法,则会执行该对象的此方法。因此,当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码。 - 反序列化一个类时,通常会伴随调用
get/set
方法注入参数,并为这个类创建一个新的实例化对象,因此会执行构造方法及静态代码块,在这种情况下,攻击者也可以挖掘gadget
来执行危险的动作。 - 根据权限最小化原则,一般情况下反序列化的类中的
readObject()
、writeObject()
、readResolve()
、writeReplace()
方法必须被声明为private void
。否则如果Serializable
的类开放writeObject
函数为public
的话,给非受信调用者过高权限,潜在有风险。 - 在Java环境中,允许处于不同受信域的组件进行数据通信,从而出现跨受信边界的数据传输。如果反序列化类中存在未加密的敏感数据,将面临泄露或被篡改的风险。
- 对非静态内部类的序列化依赖编译器,且随着平台的不同而不同,容易产生错误。对内部类的序列化会导致外部类的实例也被序列化。这样有可能泄露敏感数据。
常见样例:
反序列化操作常常出现在导入模板文件、网络通信、数据传输、日志格式化存储或者数据库存储
等业务功能出,在代码审计时可重点关注一些反序列化操作函数并判断输入是否可控。
比如可以通过对网络抓包寻找序列化数据:Java序列化的数据一般会以标记(ac ed 00 05)
开头,bas64编码后的特征为rO0AB
一些服务的传输可能存在反序列化:多平台HTTP通信、RMI、JMX。
审计策略:
主要查看这些触发点参数是否由用户可控。
比如全局搜索是否具有public
权限的一些方法:public * writeObject/readObject/readResolve/writeReplace
查看反序列化类中是否包含敏感数据。
全局查找implements Serializable
的所有内部类。
关键字:
1 | ObjectInputStream.readObject |
2.8 URL重定向
漏洞成因:
由于web站点有时需要根据不同的逻辑将用户引向到不同的页面,如典型的登录接口就经常需要在认证成功之后将用户引导到登录之前的页面。整个过程中如果实现不好的话就可能导致URL重定向问题,攻击者构造恶意跳转的链接,可以向用户发起钓鱼攻击。
审计策略:
大概思路为定位可能存在redirect
业务的代码段,审计跳转的URL是否来自于前端参数,是否具有校验和限制。
出现URL重定向主要的功能有:
- 用户登录、统一身份认证处,认证完了会通过
url=
的形式跳转到类似操作的页面 - 用户分享、收藏内容后跳转
- 跨域认证授权后进行跳转
关键字:
一些相关函数和关键字:
1 | sendRedirect |
一些常见的参数名称:
1 | redirect |
2.9 敏感信息泄露
漏洞成因:
在开发中,可能使用各种各样的框架、组件,由于配置不当或使用有误,将可能导致泄露服务器的敏感信息。
例如:swagger接口文档、Hystrix监控面板、DWR框架、druid监控平台
审计策略:
重点审计系统使用的框架、组件,根据经验查看配置,配置是否有误、是否将调试功能正式上线到生产环境中等。
2.10 代码执行/表达式执行
漏洞成因:
在Java中代码执行漏洞其实并不常见,因为在jdk9
之前的Java并不提供eval
功能,想要执行任意代码,就要动态编译,或使用反序列化、自定义ClassLoader
、结合JNDI服务、SPI机制等功能完成的任意代码执行能力。这种方式一般是安全研究员用于区别于传统的命令执行webshell
用,平常在开发时很少会遇见此类功能。
相比之下,更常见的是各种表达式的执行,包括但不限于SpEL
、OGNL
、MVEL2
、EL
等。在不同的环境下程序和框架可能使用了不同的表达式解析/模板引擎,在使用和配置有误的情况下,将导致任意表达式执行。
审计策略:
重点审计具有加载类、反序列化类、对类字节码进行操作的功能和代码,同时关注程序中使用的表达式解析组件和框架。
关键字:
1 | eval |
2.11 中间件漏洞
漏洞成因:
中间件是提供系统软件和应用软件之间连接的软件,它将应用程序运行环境与操作系统隔离,从而实现应用程序开发者不必为更多系统问题忧虑,而直接关注该应用程序在解决问题上的能力。容器就是中间件的一种。
Java常见的中间件如下:
审计策略:
直接打开pom.xml
文件查看其使用的中间件及其版本,然后在漏洞库中查找有无相应利用方案即可。
2.12 越权漏洞
漏洞成因:
在应用程序处理当前用户请求时,没有对用户权限进行校验,或校验不足、失效,导致低权限用户使用高权限功能,或同权限用户操作对方数据。
对用户的身份标识信息从可伪造的参数或headers
中获取,而不是从session
中获取的话,可能存在越权。
一些跨域的服务导向架构,尤其是一些数据处理的接口,如果缺少类似token的认证机制的话,也会存在类似的越权访问问题。
审计策略:
针对系统任意功能都可能存在越权,审计关注的是:
- 操作是否需要身份标识或其他标识
- 此标识是否由用户可控
- 是否能够可猜解,不同主体的标识是否具有规律性
- 查询信息场景下,信息是否与身份标识进行绑定
- 对应处理的函数方法中是否使用注解或其他方式对当前用户进行权限校验
- 校验能否被绕过或失效
2.13 图形验证码漏洞
漏洞成因:
- 当验证码图片的长宽由前端参数控制,并且后端没有进行校验时,攻击者可以并发生成超大的图片来进行DDOS攻击。
- 当验证码认证了一次后,无论成功还是失败,没有及时清空,就可以被重复使用,导致爆破攻击。
- 简单的图片验证码可被OCR识别,导致爆破攻击。
- 在后端逻辑校验过程中并未对前端传递验证码参数为null进行相关的逻辑判断,直接删除验证码参数或者置空值即可绕过。
审计策略:
在登陆、重要数据的增删改功能处一般会添加图形验证码功能,可以通过搜索关键字:captcha
、checkCode
等来进行审计。重点审计验证码生成逻辑,以及验证码的判断校验逻辑、顺序。
2.14 短信服务漏洞
漏洞成因:
- 如果应用程序对短信接口没有发送频率限制,或校验逻辑有误,则会导致短信轰炸漏洞。
- 如果对手机号进行校验或格式化处理逻辑有误,则会导致攻击者可通过使用空格、分隔符、手机区号、字母等方式绕过对手机号的限制,在进行缓存计数时进行绕过。
- 如果短信内容的提示有部分通过参数内容获取,则可能导致攻击者篡改消息内容,对部分用户进行顶点钓鱼攻击或垃圾短信等。
审计策略:
重点审计发送短信验证码功能的业务逻辑,一般通过关键字sms
进行检索。审计业务逻辑、缓存次数逻辑、非空判断逻辑、短信内容逻辑等等。
2.15 zip文件提取
漏洞成因:
在业务中可能存在上传压缩文件并提取的功能(ps:比如jspxcms的后台压缩包文件上传漏洞),利用此类功能可能存在如下安全问题:
- 如果提取出的文件标准路径落在解压的目标目录之外,攻击者可以利用此功能进行任意文件写入。
- 提取出的文件消耗过多的系统资源,zip算法的本性就可能会导致zip炸弹(zip bomb)的出现。由于极高的压缩率,即使在解压小文件时,比如zip、gif以及gzip编码的http内容,也可能会导致过度的资源消耗。
审计策略:
审计重点主要关注应用是否存在zip解压缩功能:
1 | FileInputStream |
如果出现了getSize需要特别关注。
2.16 硬编码
漏洞成因:
如果将敏感信息(包括口令和加密密钥)硬编码在程序中,可能会将敏感信息暴漏给攻击者。任何能够访问到class文件的人都可以反编译class文件并发现这些敏感信息。因此,不能将信息硬编码在程序中。
审计策略:
审计源代码中是否有硬编码敏感信息。
1 | password |
2.17 不安全的反射
漏洞成因:
开发人员如果提供了接口,可以由访问人员为应用程序提供确定实例化哪个类或调用哪个方法的参数值,那么就有可能创建一个贯穿于整个应用程序的控制流路径,而该路径并非是应用程序开发者最初设计的。
而攻击者可以利用这样的接口调用非预期的任意方法执行文件写入、命令执行或者其他的恶意操作。
审计策略:
查看开发人员是否对反射调用方法、反射创建类实例进行了封装,并是否在对外的接口中进行了相关的调用。
1 | Class.forName |
2.18 不安全的组件
漏洞成因:
开发人员在开发应用程序时可能会引用第三方的组件,这些组件可能被爆出过安全漏洞,但是使用者由于种种原因没有及时升级,因此可能导致存在历史遗留的问题。
组件例如:fastjson、jackson、xstream等等
框架例如:struts2、spring等等
审计策略:
关注maven和gradle等包管理软件处理的应用程序依赖,关注开发人员所使用的应用程序版本,查看是否具有存在漏洞的版本,并查看其具体调用位置,看能否构成相关漏洞。
3. 参考链接
1 | java代码审计关键字 |
发布时间: 2023-01-31
最后更新: 2023-09-26
本文标题: Java代码审计小技巧
本文链接: https://foxcookie.github.io/2023/01/31/Java代码审计小技巧/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!