前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【SDL实践指南】Foritify规则自定义刨析

【SDL实践指南】Foritify规则自定义刨析

作者头像
Al1ex
发布2025-02-12 14:15:57
发布2025-02-12 14:15:57
15800
代码可运行
举报
文章被收录于专栏:网络安全攻防
运行总次数:0
代码可运行
文章前言

Fortify SCA运用了Fortify Security研究小组开发的Fortify Source Code Analyzers的相关规则(语意规则、配置规则、数据流规则、控制流规则、结构化规则)和Code Modeling规则类型(Alias rules、Allocation rules、Buffer Copy rules、Non-Returning rules、String Length rules)去分析安全漏洞中的源代码,本篇文章将对Foritify用户自定义规则的创建和使用进行简单介绍

规则定义
规则创建

假设我们现在有如下JAVA源代码文件:

代码语言:javascript
代码运行次数:0
复制
package org.example;

public class HardPassword {
    public String iamUser="Admin";
    public String iamPassword="123456";
    public String iampassword="123456";
    public String iamPass="1234567";
    public String iam="12345678";
    public String password="123456789";

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return Password;
    }

    public void setPassword(String password) {
        Password = password;
    }
}

从上面我们可以看到这里对IAM的用户密码使用了硬编码,下面我们通过Fortify内置的规则编辑器CustomRulesEditor自定义规则来对源代码中的硬编码问题进行排查扫描,首先我们进入到Fortify的bin目录中运行CustomRulesEditor规则编辑器:

打开规则编辑器之后我们可以看到规则分类有以下四类:

  • Taint Flags/Rule Type:Taint Flags是一种标记机制,用于指示数据流的来源是否是"污点"的(即不可信的)数据源,这些标记帮助识别潜在的安全问题,例如:SQL注入、跨站脚本攻击(XSS)以及 XML外部实体(XXE)等漏洞
  • Package/Category:Package和Category用于组织和分类规则以便于管理和使用,Package为规则的包名称,表示规则所属的特定库或模块,这有助于用户快速找到相关规则并理解其上下文,Category表示规则的功能类别,例如:输入验证、安全性检查等,通过将规则分类用户可以更轻松地定位与特定安全主题相关的规则
  • Audience/Rule Type:Audience指的是规则的目标用户群体,这可能包括开发人员、安全分析师或代码审查人员等,了解受众有助于设置规则的详细程度和复杂性以适应不同技能水平的用户
  • Kingdom/Rule Type:Kingdom通常用于更高层次的分类,可能代表规则的主要领域或大类,例如:"网络安全"、"应用程序安全"等,它提供了一种结构化的方式来组织规则,使用户能够快速识别与特定领域相关的规则
  • Category/Rule Type:Category在此上下文中再次出现,表示规则的功能分类,例如:"输入验证"、"输出编码"等,这有助于用户快速了解规则的目的和作用

我们直接保持默认的"Taint Flags/Rule Type"并选择"File->Generate Rule"来创建规则:

随后会显示自定义规则的引用模板,目前主要按照漏洞类型(Category)和规则类型(Rule Type)进行分类,但是不管是何种分类都可以大致分为数据污染源Tainted规则、数据控制流规则、数据传递规则、漏洞缺陷爆发的Sink规则

在这里我们选择漏洞类型(Category)中Password Management下的"Structural Rule for Password Management"模板

随后选择规则适用的编程语言:

随后填写用于匹配密码的正则表达式(备注:在这里要多做验证测试):

代码语言:javascript
代码运行次数:0
复制
(?i)iampass(|wd|word)

配置规则存储路径:

随后可以看到根据模板生成的规则,其中总计6条匹配项,其中2项为匹配硬编码密码,另外4项为匹配空密码操作:

  • RulePackID:规则包唯一ID
  • SKU:全局唯一标识符
  • Name:规则包名称
  • Version:规则包版本
  • Description:规则包描述
  • Rules:规则组,里面可容纳多个规则
  • RuleDefinitions:规则定义

根据我们当前的规则目的我们无需去处理空密码,所以我们直接删除后面的四项,最后留下以下内容:

代码语言:javascript
代码运行次数:0
复制
<?xml version="1.0" encoding="UTF-8"?>
<RulePack xmlns="xmlns://www.fortifysoftware.com/schema/rules">
    <RulePackID>86AF47A5-E7EF-4779-AB49-123A3EC90AE2</RulePackID>
    <SKU>SKU-D:\Environment\FortifySCA\Core\config\customrules\IAM-HandCoded-rule</SKU>
    <Name><![CDATA[D:\Environment\FortifySCA\Core\config\customrules\IAM-HandCoded-rule]]></Name>
    <Version>1.0</Version>
    <Description><![CDATA[]]></Description>
    <Rules version="22.1.0">
        <RuleDefinitions>
            <StructuralRule formatVersion="22.1.0" language="java">
                <RuleID>668C7FF9-A407-4EFD-B5E7-04A70E56A611</RuleID>
                <VulnKingdom>Security Features</VulnKingdom>
                <VulnCategory>Password Management</VulnCategory>
                <VulnSubcategory>Hardcoded Password</VulnSubcategory>
                <DefaultSeverity>4.0</DefaultSeverity>
                <Description ref="desc.semantic.java.password_management_hardcoded_password">
                    <Explanation append="true"><![CDATA[This issue is being reported by a custom rule.]]></Explanation>
                </Description>
                <Predicate><![CDATA[
                FieldAccess fa: fa.field.name matches "(?i)iampass(|wd|word)" and
                                fa in [AssignmentStatement: lhs.location is fa and not rhs.constantValue.null and not rhs.constantValue is [Null:] and not rhs.constantValue == ""] and fa.field is [Field f:]*
            ]]></Predicate>
            </StructuralRule>
            <StructuralRule formatVersion="22.1.0" language="java">
                <RuleID>668C7FF9-A407-4EFD-B5E7-04A70E56A6111</RuleID>
                <VulnKingdom>Security Features</VulnKingdom>
                <VulnCategory>Password Management</VulnCategory>
                <VulnSubcategory>Hardcoded Password</VulnSubcategory>
                <DefaultSeverity>4.0</DefaultSeverity>
                <Description ref="desc.semantic.java.password_management_hardcoded_password">
                    <Explanation append="true"><![CDATA[This issue is being reported by a custom rule.]]></Explanation>
                </Description>
                <Predicate><![CDATA[
                VariableAccess va: va.variable.name matches "(?i)iampass(|wd|word)" and
                                va in [AssignmentStatement: lhs.location is va and not rhs.constantValue.null and not rhs.constantValue is [Null:] and not rhs.constantValue == ""] and va.variable is [Variable v:]*
            ]]></Predicate>
            </StructuralRule>
        </RuleDefinitions>
    </Rules>
</RulePack>
简易测试

首先将自定义规则保存到用户自定义规则目录中去(上面我们在创建时就直接保存到了自定义规则目录)——FortifySCA\Core\config\customrules

当然你也可以在${FortifyInstall}/Core/config/fortify-sca.properties进行配置自定义路径

随后启动Fortify代码扫描工具并配置加载自定义规则:

选择工程执行静态代码扫描:

随后开始执行扫描:

扫描结果如下:

在这里由于我们扫描的时候加载了默认的扫描规则,其中也包含了HardCoded Password规则所以有一部分是重复的,在验证的时候我们需要特别留意以下这里的RuleID是否和我们自定义的规则中的一致来确保我们自己定义的规则是有被加载且保证正常扫描执行到:

在这里我们为了规避默认的规则带来的影响我们可以对项目执行"重新扫描"并只勾选自定义规则:

随后得到如下结果,从中可以看到这里的大小写以及关键字的匹配都是我们预期想要的内容,所以至此规则测试完成且符合我们的预期

规则完善

在完成上面的规则的测试之后我们还需要对规则进行进一步的优化处理,包括:规则名称、修复建议、

规则名称

前面我们说过在加载规则的时候的那个路径是规则的名称而不是规则的路径,这里为了后期规则的区分我们对规则名称进行一次更改,变更的方式为更改规则中的"Name"标签属性:

随后可以看到再次加载规则的时候规则名称被成功更改:

漏洞描述

在创建自定义规则时我们有两种选择来生成关于漏洞的描述:

A、引用Foritify官方的描述

首先我们需要确定要使用的描述的标识符,描述标识符位于https://vulncat.fortify.com/en/weakness,找到要使用的描述的标识符后将自定义规则的ref属性设置为Fortify描述的标识符

描述有点偏,位于每个描述的最下面部分,例如:

代码语言:javascript
代码运行次数:0
复制
desc.semantic.java.password_management_hardcoded_password

随后变更规则,加入漏洞描述:

但是并没有什么效果:

代码语言:javascript
代码运行次数:0
复制
<?xml version="1.0" encoding="UTF-8"?>
<RulePack xmlns="xmlns://www.fortifysoftware.com/schema/rules">
    <RulePackID>86AF47A5-E7EF-4779-AB49-123A3EC90AE2</RulePackID>
    <SKU>SKU-D:\Environment\FortifySCA\Core\config\customrules\IAM-HandCoded-rule</SKU>
    <Name><![CDATA[IAM-HandCoded Password]]></Name>
    <Version>1.0</Version>
    <Description><![CDATA[]]></Description>
    <Rules version="22.1.0">
        <RuleDefinitions>
            <StructuralRule formatVersion="22.1.0" language="java">
                <RuleID>668C7FF9-A407-4EFD-B5E7-04A70E56A611</RuleID>
                <VulnKingdom>Security Features</VulnKingdom>
                <VulnCategory>Password Management</VulnCategory>
                <VulnSubcategory>Hardcoded Password</VulnSubcategory>
                <DefaultSeverity>4.0</DefaultSeverity>
                <Description ref="desc.semantic.java.password_management_hardcoded_password">
                </Description>
                <Predicate><![CDATA[
                FieldAccess fa: fa.field.name matches "(?i)iampass(|wd|word)" and
                                fa in [AssignmentStatement: lhs.location is fa and not rhs.constantValue.null and not rhs.constantValue is [Null:] and not rhs.constantValue == ""] and fa.field is [Field f:]*
            ]]></Predicate>
            </StructuralRule>
            <StructuralRule formatVersion="22.1.0" language="java">
                <RuleID>668C7FF9-A407-4EFD-B5E7-04A70E56A6111</RuleID>
                <VulnKingdom>Security Features</VulnKingdom>
                <VulnCategory>Password Management</VulnCategory>
                <VulnSubcategory>Hardcoded Password</VulnSubcategory>
                <DefaultSeverity>4.0</DefaultSeverity>
                <Description ref="desc.semantic.java.password_management_hardcoded_password">
                    <Explanation append="true"><![CDATA[This issue is being reported by a custom rule.]]></Explanation>
                </Description>
                <Predicate><![CDATA[
                VariableAccess va: va.variable.name matches "(?i)iampass(|wd|word)" and
                                va in [AssignmentStatement: lhs.location is va and not rhs.constantValue.null and not rhs.constantValue is [Null:] and not rhs.constantValue == ""] and va.variable is [Variable v:]*
            ]]></Predicate>
            </StructuralRule>
        </RuleDefinitions>
    </Rules>
</RulePack>

B、用户自定义描述

关于用户的自定义描述我们可以直接借助自定义规则编辑器来实现:

代码语言:javascript
代码运行次数:0
复制
<Abstract>:漏洞摘要
<Explanation>:漏洞描述
<Recommendations>:修复建议

随后可以看到如下效果:

变更后的规则如下:

代码语言:javascript
代码运行次数:0
复制
<?xml version="1.0" encoding="UTF-8"?>
<RulePack xmlns="xmlns://www.fortifysoftware.com/schema/rules">
    <RulePackID>86AF47A5-E7EF-4779-AB49-123A3EC90AE2</RulePackID>
    <SKU>SKU-D:\Environment\FortifySCA\Core\config\customrules\IAM-HandCoded-rule</SKU>
    <Name><![CDATA[IAM-HandCoded Password]]></Name>
    <Version>1.0</Version>
    <Description><![CDATA[]]></Description>
    <Rules version="22.1.0">
        <RuleDefinitions>
            <StructuralRule formatVersion="22.1.0" language="java">
                <RuleID>668C7FF9-A407-4EFD-B5E7-04A70E56A611</RuleID>
                <VulnKingdom>Security Features</VulnKingdom>
                <VulnCategory>Password Management</VulnCategory>
                <VulnSubcategory>Hardcoded Password</VulnSubcategory>
                <DefaultSeverity>4.0</DefaultSeverity>
                <Description>
                    <Abstract><![CDATA[IAM账号密码硬编码]]></Abstract>
                    <Explanation><![CDATA[IAM账号密码硬编码在源代码文件中存在安全风险]]></Explanation>
                    <Recommendations><![CDATA[禁止将IAM账号密码硬编码在源代码文件中]]></Recommendations>
                </Description>
                <Predicate><![CDATA[
                FieldAccess fa: fa.field.name matches "(?i)iampass(|wd|word)" and
                                fa in [AssignmentStatement: lhs.location is fa and not rhs.constantValue.null and not rhs.constantValue is [Null:] and not rhs.constantValue == ""] and fa.field is [Field f:]*
            ]]></Predicate>
            </StructuralRule>
            <StructuralRule formatVersion="22.1.0" language="java">
                <RuleID>668C7FF9-A407-4EFD-B5E7-04A70E56A6111</RuleID>
                <VulnKingdom>Security Features</VulnKingdom>
                <VulnCategory>Password Management</VulnCategory>
                <VulnSubcategory>Hardcoded Password</VulnSubcategory>
                <DefaultSeverity>4.0</DefaultSeverity>
                <Description >
                    <Abstract><![CDATA[IAM账号密码硬编码]]></Abstract>
                    <Explanation><![CDATA[IAM账号密码硬编码在源代码文件中存在安全风险]]></Explanation>
                    <Recommendations><![CDATA[禁止将IAM账号密码硬编码在源代码文件中]]></Recommendations>
                </Description>
                <Predicate><![CDATA[
                VariableAccess va: va.variable.name matches "(?i)iampass(|wd|word)" and
                                va in [AssignmentStatement: lhs.location is va and not rhs.constantValue.null and not rhs.constantValue is [Null:] and not rhs.constantValue == ""] and va.variable is [Variable v:]*
            ]]></Predicate>
            </StructuralRule>
        </RuleDefinitions>
    </Rules>
</RulePack>
使用扩展
覆盖规则

场景描述:代码审计过程中发现Foritify的某一条规则频繁错误提报,此时我们可以通过自定义规则对原规则进行覆盖处理

具体实现:

Step 1:首先记录当前规则ID

代码语言:javascript
代码运行次数:0
复制
C204F020-1CA1-4c25-A6CB-BAA69CA2DA0B

Step 2:新建一个规则覆盖当前规则ID

随便胡乱输入匹配规则

生成规则如下:

更改当前Rule ID:

随后导入规则执行扫描操作:

随后可以看到记录被移除

函数调用

场景描述:代码审计过程中发现存在具备特征的函数名称时我们可以为函数名称制定规则来实现全量检索,在检索时我们的终极目的时检索定位处所有调用该函数的位置点

具体实现:

示例代码:

代码语言:javascript
代码运行次数:0
复制
package org.example;

public class SecTest {
    public int evil(int a, int b) {
        //do something
    return a+b;
    }

    public int verify() {
        //do something
     return evil(1,2);
    }
}

新建扫描规则

选择语言:

代码语言:javascript
代码运行次数:0
复制
(?i)evil

最终规则如下:

代码语言:javascript
代码运行次数:0
复制
<?xml version="1.0" encoding="UTF-8"?>
<RulePack xmlns="xmlns://www.fortifysoftware.com/schema/rules">
    <RulePackID>96F34CB0-3E78-4410-B6FE-E4D87859E682</RulePackID>
    <SKU>SKU-D:\Environment\FortifySCA\Core\config\customrules\evil-rule</SKU>
    <Name><![CDATA[D:\Environment\FortifySCA\Core\config\customrules\evil-rule]]></Name>
    <Version>1.0</Version>
    <Description><![CDATA[]]></Description>
    <Rules version="22.1.0">
        <RuleDefinitions>
            <SemanticRule formatVersion="22.1.0" language="java">
                <MetaInfo>
                    <Group name="Accuracy">5.0</Group>
                    <Group name="Impact">5.0</Group>
                    <Group name="RemediationEffort">15.0</Group>
                    <Group name="Probability">5.0</Group>
                </MetaInfo>
                <RuleID>5C3B2AC3-9F40-4CF3-9942-88E7C76ED780</RuleID>
                <VulnCategory>FunSecScan</VulnCategory>
                <DefaultSeverity>4.0</DefaultSeverity>
                <Description/>
                <Type>default</Type>
                <FunctionIdentifier>
                    <NamespaceName>
                        <Pattern>.*</Pattern>
                    </NamespaceName>
                    <ClassName>
                        <Pattern>.*</Pattern>
                    </ClassName>
                    <FunctionName>
                        <Pattern>(?i)evil</Pattern>
                    </FunctionName>
                    <ApplyTo implements="true" overrides="true" extends="true"/>
                </FunctionIdentifier>
            </SemanticRule>
        </RuleDefinitions>
    </Rules>
</RulePack>

随后进行扫描

紧接着可以看到扫描结果如下:

备注:这里一定一定要切记,测试代码一定要符合JAVA标准语法且能够再IDEA中正常编译,不要随意乱写,否则直接扫描不出来东西,笔者这里就是在测试的时候文件名称和类名称没写一致导致始终死活出不来后期才发现这个问题,主要的原因是在使用Fortify进行扫描的时候会将源代码进行一次编译处理,如果你代码有问题,那么在编译阶段就会直接挂,根本走不到所谓的代码规则的匹配阶段,更不用说扫描出漏洞来了~

白名单类

场景描述:企业为了对用户输入的数据进行统一处理大多数情况下回制定统一的过滤函数或者验证函数来进行验证,在这种情况下我们需要对此类函数加白

具体实现:

这一步就有点意思了,我们在这里可以对调用的返回值加白或者函数整体加白使其调用点加白,另外也可以指定参数加白来适配各类场景,在这里我们选择返回值加白:

最终规则如下,数据污染溯源中如果遇到evil则会直接跳过不再报相关问题

代码语言:javascript
代码运行次数:0
复制
<?xml version="1.0" encoding="UTF-8"?>
<RulePack xmlns="xmlns://www.fortifysoftware.com/schema/rules">
    <RulePackID>4F7E0448-CB78-4B38-BB9C-CD99204A9DF0</RulePackID>
    <SKU>SKU-D:\Environment\FortifySCA\Core\config\customrules\custom-rule</SKU>
    <Name><![CDATA[D:\Environment\FortifySCA\Core\config\customrules\custom-rule]]></Name>
    <Version>1.0</Version>
    <Description><![CDATA[]]></Description>
    <Rules version="22.1.0">
        <RuleDefinitions>
            <DataflowCleanseRule formatVersion="22.1.0" language="java">
                <RuleID>937B7C98-A88E-4D73-84B9-09A02D8D3534</RuleID>
                <FunctionIdentifier>
                    <NamespaceName>
                        <Pattern>.*</Pattern>
                    </NamespaceName>
                    <ClassName>
                        <Pattern>.*</Pattern>
                    </ClassName>
                    <FunctionName>
                        <Pattern>verify</Pattern>
                    </FunctionName>
                    <ApplyTo implements="true" overrides="true" extends="true"/>
                </FunctionIdentifier>
                <OutArguments>return</OutArguments>
            </DataflowCleanseRule>
        </RuleDefinitions>
    </Rules>
</RulePack>
文末小结

Foritify自定义规则适用频次最多的应该属于SemanticRule,如果要使用更为复杂的数据流规则、控制流规则、内容规则等则自行进行配置测试即可,建议结合具体的漏洞代码展开为好~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 七芒星实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章前言
  • 规则定义
    • 规则创建
    • 简易测试
    • 规则完善
      • 规则名称
      • 漏洞描述
  • 使用扩展
    • 覆盖规则
    • 函数调用
    • 白名单类
  • 文末小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档