一款针对 Java 代码安全的扫描工具—铲子 SAST的自定义规则

阅读量40829

发布时间 : 2024-11-12 17:46:00

  1. 本文简单介绍 Java 代码审计工具铲子 SAST 的自定义规则。
  2. 铲子 SAST 地址:https://github.com/Chanzi-keji/chanzi
  3. 自定义规则采用 cyber查询语言,关于cyber语法可以参考neo4j的 cyber 语言官方手册

规则开发方法

  1. 铲子SAST的规则主要用于对图数据库进行查询,可以查询单个节点或数据流作为漏洞
  2. 在铲子中,变量都会被当作数据流节点,包括局部变量/方法定义的入参/方法调用的入参/类的成员变量,数据会在这些变量之前流动
  3. 数据流规则通常是找到数据流的起点,即source点,和 数据流的终点,即sink点,然后查找source流到sink的路径

数据流漏洞规则

  1. 下面是一条内置数据流规则,用于识别ssrf漏洞
MATCH (sourceNode:DubboServiceArg|ThriftHandlerArg|SpringControllerArg|JspServiceArg|WebServletArg|WebXmlServletArg|WebXmlFilterArg|JaxrsArg|HttpHandlerArg)
MATCH
(sinkNode)
WHERE ‘url’ IN sinkNode.selectors OR
‘URL’ IN sinkNode.selectors OR
sinkNode.AllocationClassName = ‘URL’ OR
sinkNode.AllocationClassName = ‘GetMethod’ OR
‘HttpGet’ IN sinkNode.selectors OR
(‘execute’ IN sinkNode.selectors AND ‘CloseableHttpClient’ IN sinkNode.receiverTypes) OR
(‘execute’ IN sinkNode.selectors AND ‘CloseableHttpAsyncClient’ IN sinkNode.receiverTypes) OR
(‘connect’ IN sinkNode.selectors AND ‘Jsoup’ IN sinkNode.receiverTypes) OR
(‘create’ IN sinkNode.selectors AND ‘URI’ IN sinkNode.receiverTypes) OR
(‘read’ IN sinkNode.selectors AND ‘ImageIO’ IN sinkNode.receiverTypes) OR
(‘executeMethod’ IN sinkNode.selectors AND ‘HttpClient’ IN sinkNode.receiverTypes) OR
(‘Get’ IN sinkNode.selectors AND ‘Request’ IN sinkNode.receiverTypes) OR
(‘Post’ IN sinkNode.selectors AND ‘Request’ IN sinkNode.receiverTypes) OR
(‘exchange’ IN sinkNode.selectors AND ‘RestTemplate’ IN sinkNode.receiverTypes) OR
(‘get’ IN sinkNode.selectors AND ‘HttpUtil’ IN sinkNode.receiverTypes) OR
(‘post’ IN sinkNode.selectors AND ‘HttpUtil’ IN sinkNode.receiverTypes) OR
‘openConnection’ IN sinkNode.receivers
MATCH
p = (sourceNode)-[ *..30]->(sinkNode)
RETURN
p AS path

 

如何查询source点
  1. 铲子自动识别了一些常见框架的请求入口,并打上标签,用户可以利用这些标签快速找到source点,比如下列标签:DubboServiceArg|ThriftHandlerArg|SpringControllerArg|JspServiceArg|WebServletArg|WebXmlServletArg|WebXmlFilterArg|JaxrsArg|HttpHandlerArg
  2. 用户如果觉得这些标签不满足需求,也可以根据各种条件找到自己关心的source点,比如springmvc可以利用RequestMapping GetMapping等注解查找,比如下边这条规则就是用注解进行识别的source点
MATCH
(sourceNode:Argument)
WHERE
‘RequestMapping’ IN sourceNode.methodAnnotations OR
‘GetMapping’ IN sourceNode.methodAnnotations OR
‘PostMapping’ IN sourceNode.methodAnnotations OR
‘DeleteMapping’ IN sourceNode.methodAnnotations OR
‘PutMapping’ IN sourceNode.methodAnnotations
MATCH
(sinkNode)
WHERE
‘queryForMap’ IN sinkNode.selectors OR
‘queryForObject’ IN sinkNode.selectors OR
‘queryForList’ IN sinkNode.selectors OR
‘queryForRowSet’ IN sinkNode.selectors OR
‘batchUpdate’ IN sinkNode.selectors OR
(‘query’ IN sinkNode.selectors AND ‘JdbcTemplate’ IN sinkNode.receiverTypes)
MATCH
p = (sourceNode)-[*..30]->(sinkNode)
RETURN
p AS path

 

如何查询sink点
  1. 识别sink点通常可以使用方法调用时的方法名,方法所属对象的对象名,方法所属对象的类型名,构造方法的方法名等,也可以多个条件组合使用
  2. 比如runtime.exec(cmd),这样一个调用,runtime是receiver exec是selector Runtime是receivertype ,我们就可以根据receiver receivertype selector等信息找到cmd作为sink点
  3. 当然也有可能sink点处的数据流节点是receiver,比如 ssrf中的,url.openConnection(), 这里的url作为污点,并不是方法调用的参数,而是receiver,规则会有所不同,写法可以参考铲子的内置规则

一条参考规则如下:

MATCH
(sourceNode:DubboServiceArg|ThriftHandlerArg|SpringControllerArg|JspServiceArg|WebServletArg|WebXmlServletArg|WebXmlFilterArg|JaxrsArg|HttpHandlerArg)
MATCH
(sinkNode)
WHERE
(‘exec’ IN sinkNode.selectors AND ‘Runtime’ IN sinkNode.receiverTypes) OR
sinkNode.AllocationClassName = ‘ProcessBuilder’ OR
(‘command’ IN sinkNode.selectors AND ‘ProcessBuilder’ IN sinkNode.receiverTypes) OR
(‘eval’ IN sinkNode.selectors AND ‘ScriptEngine’ IN sinkNode.receiverTypes) OR
(‘evaluate’ IN sinkNode.selectors AND ‘GroovyShell’ IN sinkNode.receiverTypes)
MATCH
p = (sourceNode)-[*..30]->(sinkNode)
RETURN
p AS path

 

关于净化处理
  1. 铲子的内置规则均没有考虑净化处理,净化处理的方式没有固定的写法,不同的公司有不同的安全SDK,但更多是研发根据自己的理解进行漏洞修复,比如SQL注入最常用的修复是"预编译",xss最常用的修复是前端框架自身的安全输出,而非净化函数
  2. 如果用户有特定净化的方式可以利用cyber的语法的过滤功能,进行规则优化,筛选掉不需要的漏洞数据流

单节点漏洞规则

  1. 单节点查询通常比较简单,直接通过节点的属性匹配即可
  2. 下面是一条单节点规则,用于识别actuator配置不当
MATCH
(sinkNode:YmlKeyValue|PropertiesKeyValue)
WHERE
sinkNode.name = ‘management.endpoints.web.exposure.include’ AND (sinkNode.value = ‘*’ OR sinkNode.value CONTAINS ‘heapdump’ )
RETURN
sinkNode AS path

 

  1. 下面是一条单节点规则,用于识别fastjson版本问题
MATCH
(sinkNode:PomDependency)
WHERE
sinkNode.groupId = ‘com.alibaba’ AND sinkNode.artifactId = ‘fastjson’ AND sinkNode.version < ‘1.2.83’
RETURN
sinkNode AS path

 

  1. 当然也可以使用正则,或前缀/后缀匹配,类似下边这样(pom.xml中的依赖组件版本号如果使用了${},铲子会自动识别并替换成真实版本号)
MATCH
(sinkNode:PomDependency)
WHERE
sinkNode.groupId = ‘org.apache.shiro’ AND sinkNode.artifactId = ‘shiro-core’ AND sinkNode.version =~ ‘1\\.(1|2|3|4|5|6|7|8|9|1[0-1]|12)\\..*’
RETURN
sinkNode AS path

 

MATCH
(sinkNode:PomDependency)
WHERE
sinkNode.groupId = ‘org.apache.struts’ AND sinkNode.artifactId = ‘struts2-core’ AND sinkNode.version STARTS WITH ‘2.’
RETURN
sinkNode AS path

 

加载自定义规则

  1. 把写好的自定义规则放在一个文件夹
  2. 规则文件命名的结构需要与内置规则保持一致,写好的规则可以直接在规则管理的编辑器进行运行测试,运行于当前打开的任务
  3. 比如 any_mybatis_sqli.cypher , 数据流规则格式为 source类型_sink类型_漏洞类型.cyphper
  4. 比如 pom_actuator_misconfig.cypher, 单节点规则格式为 文件类型_组件类型_漏洞类型.cypher
  5. 加载规则:在菜单里找到规则管理,自定义规则tab里点击加载规则即可

规则完整结构

  1. 规则需要包括: 规则查询语句 漏洞描述 漏洞修复建议 三个部分;Chanzi-Separator关键字用于分割三个部分;漏洞描述和修复建议用注释符包裹;下面是一条完整的例子
MATCH
(sourceNode:DubboServiceArg|ThriftHandlerArg|SpringControllerArg|JspServiceArg|WebServletArg|WebXmlServletArg|WebXmlFilterArg|JaxrsArg|HttpHandlerArg)
MATCH
(sinkNode)
WHERE
‘setByteStream’ IN sinkNode.selectors OR
( ‘read’ IN sinkNode.selectors AND ‘SAXReader’ IN sinkNode.receiverTypes) OR
( ‘parse’ IN sinkNode.selectors AND ‘XMLReader’ IN sinkNode.receiverTypes) OR
( ‘build’ IN sinkNode.selectors AND ‘SAXBuilder’ IN sinkNode.receiverTypes) OR
( ‘parse’ IN sinkNode.selectors AND ‘SAXParser’ IN sinkNode.receiverTypes) OR
( ‘parse’ IN sinkNode.selectors AND ‘DocumentBuilder’ IN sinkNode.receiverTypes) OR
( ‘parse’ IN sinkNode.selectors AND ‘Digester’ IN sinkNode.receiverTypes) OR
( ‘parseText’ IN sinkNode.selectors AND ‘DocumentHelper’ IN sinkNode.receiverTypes) OR
( ‘unmarshal’ IN sinkNode.selectors AND ‘Unmarshaller’ IN sinkNode.receiverTypes)
MATCH
p = (sourceNode)-[*..30]->(sinkNode)
RETURN
p AS path
/*
Chanzi-Separator
<h5>漏洞描述</h5>
XXE(XML外部实体攻击,XML External Entity Attack)漏洞是一种影响XML处理器的安全漏洞。当XML文档允许引用外部实体时,如果没有得到正确处理,攻击者可以利用这个漏洞来读取服务器上的文件、执行拒绝服务攻击(DoS),甚至在某些情况下执行远程服务器的攻击。以下是XXE漏洞的基本原理:
XML和DTD:XML文档可以使用DTD(文档类型定义)来定义合法的文档结构。DTD可以是内部定义的,也可以引用外部定义。
外部实体引用:在DTD中,可以定义外部实体,这些实体可以引用外部资源,如文件系统中的文件或网络上的资源。
漏洞触发:如果XML解析器配置不当,允许引用外部实体,攻击者可以构造特殊的XML输入,其中包含对外部实体的引用。
文件读取:攻击者可以利用XXE漏洞尝试读取服务器上的敏感文件,例如配置文件、源代码等。
拒绝服务攻击:攻击者可以构造一个指向大型文件或无限循环的外部实体引用,导致XML解析器消耗大量资源,从而实现拒绝服务攻击。
远程服务器攻击:如果允许通过网络引用外部资源,攻击者可以利用这一点来发起远程服务器攻击,例如尝试读取远程服务器上的文件。
配置不当的XML解析器:很多XML解析器默认允许处理外部实体,如果应用程序没有正确配置解析器,就可能受到XXE攻击。
防御不足:如果应用程序没有实施足够的安全措施来防止XXE攻击,就可能容易受到攻击。
Chanzi-Separator
<h5>修复建议</h5>
修复Java中XXE(XML外部实体攻击)漏洞需要开发者采取以下步骤和策略:
禁用外部实体处理:确保XML解析器配置为禁用对外部实体的解析。这可以通过设置XML处理器的属性来完成。
使用安全的解析器:选择不容易受到XXE攻击的XML解析器,例如使用不支持外部实体解析的解析器。
输入验证:对所有传入的XML数据进行严格的验证,确保它们不包含对外部实体的引用。
使用白名单:如果应用程序需要引用外部资源,使用白名单来限制可引用的资源,只允许特定的、已知安全的资源被引用。
限制DTD使用:避免在XML文档中使用DTD(文档类型定义),或者确保DTD是安全的,不包含对外部实体的引用。
错误消息处理:确保错误消息不会泄露有关XML解析器配置或文件路径的信息。
使用安全的库:使用成熟的库来处理XML数据,避免使用可能容易受到XXE攻击的旧库。
使用安全的XML处理API:在Java中,使用如javax.xml.parsers.DocumentBuilder时,确保禁用外部实体的解析,例如通过设置DocumentBuilderFactory的setFeature(“http://apache.org/xml/features/disallow-doctype-decl”, true)。
配置安全的XML解析器:如果使用SAX解析器,确保配置它以避免解析外部实体,例如使用setEntityResolver方法来返回一个自定义的EntityResolver。
使用 json 代替 xml:针对用户的输入,通常建议优先考虑使用 json 格式代替 xml 格式,有更高的安全性,xml 由于其复杂的 dtd、scheme 等机制更易受到攻击。
Chanzi-Separator
*/

 

规则管理界面

  1. 在当前打开的任务运行测试xxe规则的效果(下边窗口输出的是简化后的数据流path) image

 

本文由chanziSAST原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/300955

安全客 - 有思想的安全新媒体

分享到:微信
+10赞
收藏
chanziSAST
分享到:微信

发表评论

chanziSAST

铲子是一款简单、好用、价格厚道的 Java 代码安全扫描工具,我们努力让客户把发现代码安全漏洞变得简单、低成本!

  • 文章
  • 5
  • 粉丝
  • 0

热门推荐

文章目录
内容需知
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 三六零数字安全科技集团有限公司 安全客 All Rights Reserved 京ICP备08010314号-66