Fortify自定义规则编写教程(二):数据流规则设计介绍
上次我们示例中建立的规则就是一个通用的数据流规则之一。数据流规则一共分为5类:
DataflowEntryPointRule
DataflowSourceRule
DataflowPassthroughRule
DataflowSinkRule
DataflowCleanseRule
以下简称为EntryPoint规则,Source规则,Passthrough规则,Sink规则和Cleanse规则。
数据流规则中一个重要的概念是TaintFlags(污染标记,以下简称为Taint),它一般贯穿于数据流中,作为最终判定问题的重要依据。Taint是可以自定义的,例如定义一个名为TESTTAINT的Taint,在规则中,可以对其进行如下几种操作:
1.生成一个Taint,例如 +TESTTAINT
2.消减一个Taint,例如 -TESTTAINT
一个Taint需要对其进行声明和描述,参考如下样例:
/RulePack/Rules/TaintFlagDeclarations:
Taint声明中,类型有3种:neutral,specific和general
1.neutral:主要用于"VALIDATED_xxx"类型的taint,即无害的taint
2.specific:自定义的taint,但不会影响到其他sink规则,官方规则不会报出这个taint的相关缺陷。
3.general:默认行为的taint,会影响到其他sink规则,即官方规则会报出这个taint的相关缺陷。
/RulePack/Rules/TaintFlagDescriptions:
下面介绍各种类型的数据流规则:
1.EntryPoint规则:
入口规则,以C语言为例,main函数就是一个入口。入口规则用的不多,官方规则基本已涵盖,入口规则一般会引入ARGS(即标准输入参数)的Taint,即main函数的参数(也有可能不引入Taint)。
2.Source规则:
源头规则,一般用于引入Taint,例如函数recv(),用于接收网络数据,则调用recv即会引入NETWORK(即网络数据的Taint)标记。若产品中遇到自定义的recv函数,例如封装后为xxx_recv,则可以为其制定一条Source规则(引入NETWORK标记)。
3.Passthrough规则:
贯穿规则,一般用于转换Taint(可消减,可新增,也可不变):
(1)例如sprintf()函数,输入参数经过处理,输出到输出参数时,会消减掉NOT_NULL_TERMINATED标记,即确保输出参数是以NULL结尾的字符串。
(2)例如strlen()函数,输入参数经过处理,输出到输出参数时,会新增NUMBER标记,即输出参数为数值;同时也会消减掉其他标记(NOT_NULL_TERMINATED,NOT_NULL_TERM_TRUNCATE,NULL_TERMINATED)
(3)例如sscanf()函数,Taint流过的时候不变,输入参数经过处理,输出到输出参数时Taint标记保留。
4.Sink规则:
汇入规则,我更习惯称之为‘发作’规则,因为最终的问题往往是在此规则上报出的。流入Sink的Taint如果满足判断条件,则报为缺陷。以之前的NETWORK标记为例,如果Sink规则的函数为system(),则在经过判断后,认为这是命令注入缺陷(网络数据直接执行OS命令,远程可执行类的缺陷);但如果中途被Passthrough规则转换为NUMBER标记,则不会报为问题(数值数据无法成为OS命令被执行)。
5.Cleanse规则:
清理规则,针对特定的Taint进行清理(如果不指定特定Taint,则会清理所有Taint)。例如std::vector的clear()方法,会将vector清空,即所有Taint也将被清空。如果产品中有特定的校验函数,可以使用Cleanse规则,规避较多的误报。
后面的教程中,我们将以实例的方式讲解如何自行制定数据流规则,辅助产品扫描。
作者:陈辉军
- 点赞
- 收藏
- 关注作者
评论(0)