Juliet test suite漏洞类别分析
一般来说,测试用例侧重于底层平台上可用的功能,而不是使用第三方库。
尽管C和C++是不同的编程语言,但由于C++通常是C的superset,因此它们被视为一个unit。此外,大多数软件保证工具都支持C和C++。
C测试用例代码以C89标准为目标,因此可以使用各种可能不支持C语言更新版本的工具来编译和分析测试用例。
Test Case Scope
test cases selection
CAS在为测试用例选择缺陷类型时使用了多个来源:
测试用例开发团队在软件保障方面的经验
CAS先前工具研究中使用的缺陷类型
供应商关于其工具识别的缺陷类型的信息
MITRE常见弱点枚举(CWE)中的弱点信息
尽管每个测试用例都使用CWE标识符作为其名称的一部分,但创建测试用例并不需要针对缺陷类型的特定CWE条目。测试用例是为所有适当的缺陷类型创建的,并且每一个测试用例都用最相关的CWE条目命名。
test case statistic
测试案例涵盖了2011年CWE/SANS 25大最危险软件错误中的11个。在测试用例未涵盖的前25个测试用例中的14个CWE条目中,有10个是不适合CAS测试用例结构的设计问题。其他四个并不是C/C++特有的,而是在相关的Java测试用例中介绍的。

Juliet Test Suite v1.2 for C/C++中添加了新的缺陷。2012年的C/C++测试用例总数为61387个,而2011年为57099个。这意味着增长了7.5%。
test cases naming
测试用例是针对一种类型缺陷的可构建代码,通常包含一个或多个执行类似于有缺陷构造的功能的无缺陷构造
Naming Scheme
测试样例以CWE作为命名和组织的基准。测试样例努力为目标缺陷使用最具体的CWE条目。每个测试用例文件只与一个CWE条目相关联。
一个测试样例由以下几部分组成:
与漏洞最密切相关的CWE条目的识别号和可能缩短的cwe名称。
functional variant:它比cwe条目更能明确地指出漏洞。
一个与flow variant相关的两位数:其表示的是测试样例里面用的数据流和控制流类型。flow variant“01”是最简单的漏洞形式,既不包含数据流也不包含控制流。
测试样例使用的编程语言。它表示在测试样例的扩展名中。
Test Case Functional Variants
每个测试用例都有一个functional variant,它也是缺陷类型的同义词。它应该尽可能短,通常只是测试用例中使用的类型或函数的名称。
Key Strings in Functional Variant Names
有一个关键字字符串可以出现在functional variant name中,以指示测试用例特征。此字符串由管理测试用例、构建过程和结果评估的脚本使用。由于用于生成大多数测试用例的软件的性质,此字符串可能在功能变体名称中出现不止一次
test case flow variants
测试用例中存在的控制流或数据流的类型由“flow variant”编号指定。具有相同flow variant编号(但CWE条目或“功能变量”不同)的测试用例使用相同类型的控制流或数据流。
具有除“01”以外的flow variants的测试用例被称为“更复杂”的测试用例。那些具有从“02”到“22”(包括“02”和“22”)的flow variant的测试用例涵盖了各种类型的控制流结构,并被称为“控制流”测试用例。flow variants为“31”或更大的测试用例涵盖了各种类型的数据流结构,被称为“数据流”测试用例。22到31之间是留下为未来的补充使用。
Test Case Files
测试用例文件是指只与一个测试用例关联的文件(与通常由多个测试用例使用的支持测试用例的文件相反)。单个测试用例由一个或多个测试用例文件组成。

Test Case File Names


Sub-file Identifier
大多数漏洞的简单形式可以包含在一个源代码文件中,但有些测试用例由多个文件组成。测试用例可能被拆分为多个文件,并且每个文件都使用不同类型的字符串来标识测试用例中的每个文件。
一些C++漏洞是类中固有的,需要为有漏洞和无漏洞的构造分别提供文件。
一些数据流测试用例涉及不同源代码文件中函数之间的数据流。在这些测试用例中,测试用例将在用字符串“a”标识的文件中“启动”,例如“CWE476_NULL_Pointer_Dereference__char_54a.c” “a”文件中的函数会调用“b”文件中函数,后者可能会调用“c”文件等中的函数。
一些数据流测试用例涉及虚拟函数调用之间的数据流。在这些测试用例的C++版本中,头文件(.h)用于定义虚拟函数,并且实现发生在单独的源文件(.cpp)中
一些数据流测试用例涉及类constructor函数和destructor函数之间的数据流。在这些测试用例中,头文件(.h)用于定义constructor函数和destructor函数,并且实现发生在单独的源文件(.cpp)中。
test case design
大多数涵盖漏洞的测试用例可以归为任意函数(非基于类的漏洞)然而有些漏洞,被称为基于类的漏洞,是在c++类中固有的,并且需要在测试用例设计中区别处理。一个基于类漏洞的例子是:
C++ test case CWE416_Use_After_Free__operator_equals_01
虚拟函数、构造函数/析构函数和 bad-only test cases是唯一的。虚拟函数和构造函数/析构函数测试用例需要多个文件,而只有 bad-only test cases只用于测试缺陷,而不是像所有其他测试用例那样同时测试缺陷和非缺陷。
所有C/C++测试用例还在主文件中定义了一个“main”函数。当同时编译多个测试用例时,不使用此主函数。但是,它可以用在构建单个测试用例。
在C/C++测试用例中,必须在编译时定义预处理器宏INCLUDEMAIN,以便将此主函数包含在编译中。
Non-Class-Based Flaw Test Cases
Required Functions
对于非C++类的漏洞样例必须定义好函数和坏函数。(注意:少数测试用例仅被认为是坏的,不包含好函数的实现。)
对于使用多个文件的测试用例,以下函数在“a”子文件中定义
1.测试用例的“主文件”是多文件测试用例中“a”个子文件的通用术语
2.测试用例的“主文件”是单文件测试用例的唯一文件。
primary bad function
每个测试用例在主文件中只包含一个主要的坏函数。在许多更简单的测试用例中,该函数包含有缺陷的构造,但在其他测试用例中该函数调用包含该缺陷的其他“sink”或“helper”函数。
The primary bad function:
For C, is named with the test case name followed by the string “_bad,” such as “CWE78_OS_Command_Injection__char_connect_socket_execl_01_bad().”
For C++, is named bad() and is in a namespace that is unique to the test case. The function is not part of a C++ class.
Takes no parameters and has no return value.
The name of the primary bad function matches the following regular expression:
^(CWE.*_)?bad$
primary good function
每个测试用例在主文件中只包含一个主好函数(与主坏函数相同的文件)。这个好函数中唯一的代码是对每个次要好函数(secondary good functions)的调用。
The primary good function:
For C, this function is named with the test case name followed by the string “_good,” such as “CWE78_OS_Command_Injection__char_connect_socket_execl_01_good().”
For C++, this function is named good() and is in the namespace that is unique to the test case. The function is not part of a C++ class.
Takes no parameters and has no return value.
The name of the primary good function matches the following regular expression:
^(CWE.*_)?good$
Secondary Good Function(s)
不基于类的漏洞样例在主文件夹中也包含一个或多个次要好函数。某些bad-only测试样例中,不包含任何次要好函数。许多更简单的测试用例,这些次要的好函数包含了实际的无漏洞结构。次要良好函数的数量取决于测试用例的缺陷类型以及存在多少类似于该缺陷的无缺陷构造。许多测试用例只有一个次要的好功能,但其他测试用例可能有更多。
次要好函数有三种命名规则:
goodG2B, goodG2B1, goodG2B2, goodG2B3, etc. –good source bad sink
goodB2G, goodB2G1, goodB2G2, goodB2G3, etc. –bad source good sink
good1, good2, good3, etc. – 当上述条件不适用时,这是这些函数的“默认”或“通用”名称
正则表达式:^good(\d+|G2B\d*|B2G\d*)$
次要好函数与主要坏函数和主要好函数具有相同的参数和返回类型。此外,次要好函数还具有以下特点:
在C和C++测试用例中,次要的好函数是静态作用域的。因此,它们只能在源代码文件中访问,这样可以防止名称冲突
在C++测试用例中,次要的好函数位于测试用例唯一的命名空间中。这些函数不是C++类的一部分。
optional functions
除了required functions,测试样例还可能定义“helper” “source” “sink”函数
helper function
helper functions用于当最简单的漏洞也不能包含在单个函数中的测试样例中。在更复杂的测试用例中用于创建数据流模式的函数不被视为helper functions,因为它们不是漏洞构造的一部分。
例子:
涉及可变参数函数的测试样例, such as in the C test case CWE134_Uncontrolled_Format_String__char_console_vprintf_01.
未使用参数的测试样例, such as in the C test case CWE563_Unused_Variable__unused_parameter_variable_01.
helper functions总是被分为bad function或good function。bad function和good function可能包含不同的代码或完全相同的代码。
有bad code的helper function被称为helper bad
如果可能的话,helper function的作用域是静止的。
source and sink function
包含数据流漏洞的测试样例使用source functions和sink functions,它们是从彼此调用的,或者从主要的坏函数或好函数调用的。每个源函数或汇函数都特定于测试用例的坏函数,或者只针对一个次好函数。
Bad source and sink functions are generally named “BadSource” and “BadSink.”
Good source functions are generally named “goodG2BSource,” “goodG2B1Source,”“goodB2GSource,” “goodB2G2Source,” etc.
Good sink functions are generally named “goodG2BSink,” “goodG2B1Sink,”“goodB2GSink,” “goodB2G2Sink,” etc.
正则表达式:
^(CWE.+_)badSource(_[a-z])?$
^(CWE.+_)badSink(_[a-z])?$
^(CWE.+_)good(G2B\d*|B2G\d*)?Source(_[a-z])?$
^(CWE.+_)good(G2B\d*|B2G\d*)?Sink(_[a-z])?$
class based flaw test case
基于C++类的漏洞的测试用例设计略有不同,因为坏的和好的构造不能包含在一个任意函数中。这些测试用例在单独的文件中使用单独的类。
Bad File for Class-Based Flaws
在一个基于类的漏洞的测试样例中,bad file:
名字末尾带_bad
包含一个必需的坏函数,其签名类似于非基于类的漏洞的测试用例中的坏函数。此函数利用此测试用例的坏类来练习正在测试的漏洞。
如果文件中只有一个类,则将其命名为“BadClass”。如果漏洞需要一个基类和一个子类,则这些类位于同一文件中,并命名为“Badbaseclass”和“badderivedclass”
有一个调用坏函数的主函数。与针对非类漏洞的测试用例中的main函数一样,此函数仅用于测试或构建测试用例的单独二进制文件。
Good File for Class-Based Flaws
在一个基于类的漏洞的测试样例中,good file:
名字末尾带_good1
包含一个名为“good”的必需主good函数,其签名类似于非基于类的缺陷的测试用例中的“good“函数。
包含至少一个必须的secondary good function“good1”来匹配文件名。
在C++中,如果文件中只有一个类,则将其命名为“GoodClass”。如果无漏洞构造需要基类和子类,则这些类位于同一文件中,并命名为“GoodBaseClass”和“GoodDerivedClass”
具有调用primary good function的主函数。
Virtual Function Test Cases
一些测试样例使用了virtual functions。为了将这些类型的测试用例放入测试用例套件中,它们的设计与前面描述的“传统”测试用例略有不同。
一个C++Virtual Function Test Cases包含五个文件:
1. Header file:此文件定义基类,并将基类中名为“action”的函数声明为纯虚拟函数。它还定义了坏类和好类,并在那些将从基类实现“action”函数的类中声明“action”功能。该文件的扩展名是标准的“.h”
2. root file:这个文件包含坏函数和好函数的实现。
3. Bad implementation file:该文件为一个坏的类实现了action function,包含字符串“bad”作为子文件标识符。
4. GoodG2B implementation file:这个文件为一个好的类实现了“action”函数,该类使用了一个坏的sink。
5. GoodB2G implementation file:这个文件为一个好的类实现了“action”函数,该类使用了一个好的sink。
Constructor/Destructor Test Cases
一些测试用例,包含类的构造函数和析构函数之间的数据流。包含数据流的“source”的代码包含在构造函数中,包含数据流“sink”的代码则包含在析构函数中。与虚拟功能函数用例一样,这些类型的测试用例的设计与“传统”测试用例略有不同,以便它们适应测试用例套件。
一个c++ constructor/destructor Data Flow test case有五个文件:
1. Header file:此文件定义了坏类和好类,这些类中的每一个都包含一个构造函数和析构函数。该文件的扩展名是标准的“.h”
2. root file:这个文件包含坏函数和好函数的实现。文件名包含字母“a”作为子文件标识符,是一个C++源文件。
3. Bad implementation file:该文件为一个坏的类实现了constructor and destructor,包含字符串“bad”作为子文件标识符。
4. GoodG2B implementation file:这个文件为一个好的类实现了constructor and destructor,该类使用了一个坏的sink。
5. GoodB2G implementation file:这个文件为一个好的类实现了constructor and destructor,该类使用了一个好的sink。
Bad-only Test Cases
在漏洞样例的设计过程中,在少数情况下解决检测的漏洞的无漏洞构造无法被正确的生成。因此,只有少数的测试样例被认为是bad-only,因为它们只包含有漏洞的构造。
bad only测试用例与其他测试用例在以下方面有所不同:
All bad-only test cases are non-class-based.
No bad-only test cases contain Data Flows.
bad only测试样例与不基于类的测试样例具有相同的命名规则。需要注意的是,这些测试案例应排除在任何试图确定静态分析工具报告的假阳性数量的分析之外。
更多推荐



所有评论(0)