眼镜蛇(Cobra)是一款定位于静态代码安全分析的工具,目标是为了找出源代码中存在的安全隐患或者漏洞。
由于开发人员的技术水平和安全意识各不相同,导致可能开发出一些存在安全漏洞的代码。
攻击者可以通过渗透测试来找到这些漏洞,从而导致应用被攻击、服务器被入侵、数据被下载、业务受到影响等等问题。 “源代码安全审计”是指通过审计发现源代码中的安全隐患和漏洞,而Cobra可将这个流程自动化。
而本文主要讲解如何进行Cobra的规则库编写,希望对cobra有定制需求的朋友有所帮助。
十大规则字段
Cobra的规则文件格式是xml,因此在文件的开头往往需要声明版本和编码,然后以< cobra >标签表明这是个cobra的规则文件:
而规则的具体内容就写在< cobra >标签内,而Cobra提供了十种字段来让开发者描述规则,接下来我将详细讲解这十大规则字段。
name字段
name是由Cobra提供的用来描述规则的名字的字段,内容是字符串类型,因此在编写规则前先给你的规则取个合适的名字吧:
language字段
language是由Cobra提供的用来声明规则适用的编程语言的字段,内容是字符串类型,当在language字段声明了指定语言时,扫描器将不会使用该规则检测language以外的编程语言代码:
上图所示,该规则只会由于检测以.php/.php3/.php4/.php5为后缀的文件代码,而Cobra支持检测的语言以及对应文件后缀详见:Cobra语言支持。
如果希望编写的规则适用于所有语言,则如下编写language字段:
<language value="*"/>
level字段
level是由Cobra提供的用来声明该漏洞风险等级的字段,内容为一个整型数字,一共有十种风险等级,为1-10级,等级越高则说明危害越高。一般来说,风险等级按以下标准来设定:
等级 | 分值 | 描述 |
---|---|---|
严重 | 9-10 | 1.可获取服务器权限; 2.严重信息泄露; |
高危 | 6-8 | 1.敏感信息泄露; 2.越权; 3.任意文件读取; 4.SQL注入; 5.git/svn泄露; 6.SSRF; |
中危 | 3-5 | 1.XSS; 2.URL跳转; 3.CRLF; 4.LFI; |
低危 | 1-2 | 1.CSRF; 2.JSONP劫持; 3.异常堆栈信息; 3.PHPINFO; 4.路径泄露; 5.硬编码密码; 6.硬编码内网IP域名; 7.不安全的加密方法; 8.不安全的随机数; 9.日志敏感记录; |
我们声明一个风险等级为3的漏洞:
status字段
status字段设置了是否开启该规则的扫描,使用on/off来标记,只有当标记为on时,该规则才会生效:
match字段
match字段是用来声明规则具体内容的字段,而在< match > 标签的内部就是规则的具体内容。
match是Cobra规则的核心字段,因为它定义了规则的具体内容和检测方法,而在编写规则前需要先定义match的唯一属性:mode。
mode属性
mode属性决定了match的检测模式,当mode属性的值不同时,代码检测的模式不同,比如使用“regex-only-match”模式时,就是进行正则匹配的方式扫描代码,找出所有与正则表达式相匹配的源码,并将之标记为漏洞。而当检测模式设置为“function-param-controllable”时,就会检测所设定函数的所有调用,如果传入该函数的参数是用户可控的,则标记为漏洞。而mode一共有四种检测模式:
Mode | 类型 | 默认模式 | 支持语言 | 描述 |
---|---|---|---|---|
regex-only-match | 正则仅匹配 | 是 | * | 默认是此模式,但需要显式的写在规则文件里。以正则的方式进行匹配,匹配到内容则算作漏洞 |
regex-param-controllable | 正则参数可控 | 否 | PHP/Java | 以正则模式进行匹配,匹配出的变量可外部控制则为漏洞 |
function-param-controllable | 函数参数可控 | 否 | PHP | 内容写函数名,将搜索所有该函数的调用,若参数外部可控则为漏洞 |
find-extension | 寻找指定后缀文件 | 否 | * | 找到指定后缀文件则算作漏洞 |
规则内容
规则内容是写在< match >标签内的具体检测内容,编写的规则内容要与mode属性相对应,不然无法检测,如当使用“regex-only-match”模式时,规则内容就应该是正则表达式,而使用“function-param-controllable”模式时,规则内容就应该是函数名。
我们编写一个测试规则内容,以正则匹配的方式来匹配< test >标签:
我们编写一个php文件,在里面写入代码:echo ‘<test> just for test </test>’
,然后使用我们编写的规则对其进行检测,检测结果:
如图所示,能够按照规则检测出恶意代码。
match2字段
由于仅仅使用match一个字段无法应对许多特殊的漏洞规则编写需求,因此Cobra提供了两个字段来辅助match字段更好地进行规则编写,而match2字段就是其中之一。match2的作用是在match成功匹配到的前提下,进行二次匹配,只有match2也匹配成功,则标记为漏洞。而match2拥有block属性,在编写二次规则前需要先给block属性赋值。
block属性
block属性是match2的唯一属性,其定义了二次匹配的匹配范围,比如当block的值为“in-current-line”时,二次匹配范围则在match匹配到的行中,而当block的值为“in-file”时,则范围会在match匹配到的位置所在的文件中。block属性具体可以取的值如下表所示:
| 区块 | 描述 |
| - | :-: |
| in-current-line | 由第一条规则触发的所在行 |
| in-function | 由第一条规则触发的函数体内 |
| in-function-up | 由第一条规则触发的所在行之上,所在函数体之内 |
| in-function-down | 由第一条规则触发的所在行之下,所在函数体之内 |
| in-file | 由第一条规则触发的文件内 |
| in-file-up | 由第一条规则触发的所在行之上,所在文件之内 |
| in-file-down | 由第一条规则触发的所在行之下,所在文件之内 |
规则2内容
规则2内容是写在<match2>
标签内的二次检测规则,拿上面的例子,我们继续尝试编写二次匹配规则,在匹配<test>
标签的前提下,检测该行内出现‘not’这个单词则视为漏洞:
对测试用例进行检测结果:
可以看见,语句echo ‘<test> just for test </test>’
已经不被视为漏洞,因为该行中不包含match2所要求的not单词。而echo ‘<test> not just for test </test>’
则与我们期待的一样被标记为漏洞。
多次使用
值得一提的是,由于match2字段是用来辅助match而存在的字段,因此它并不能独立于match字段存在,只有match字段存在时,它才能被使用。而match2可以被多次使用,绑定于同个match进行多次匹配,我们尝试编写多个match2进行测试:
检测结果:
可以看到,多次使用的match2的结果并不是match+match2(1)+match2(2),而是match+match2(1)或match+match(2)。
repair字段
上文说过,Cobra使用了2个字段来辅助match字段进行更好的匹配,除了match2字段,另一个就是repair字段。从用法上来说,repair字段和match2字段基本上一模一样,但是他们的作用却是完全相反。在match匹配的前提下,当match2二次匹配成功时,标记为漏洞,而repair却是二次匹配成功时,视为漏洞已被修复,不再标记为漏洞。
继续上面的例子,我们编写二次匹配规则,在匹配<test>
标签的前提下,检测该行内出现‘not’这个单词则视为漏洞已被修复:
检测结果:
可以看到,检测结果呈现与match2完全相反的结果,这是因为match的前提下,该行匹配到not则不视为漏洞,所以最后就呈现了这种结果。
当match2字段和repair字段同时使用时,repair的优先级高于match2。
solution字段
这个字段很好理解,当漏洞被标记时显示解决方法,内容为字符串,且会直接显示在被标记的漏洞下。往往在该字段内描述详细的解决方法以帮助商家修复漏洞,编辑:
直接显示:
test字段
该字段用来写规则对应测试用例,在<test>
字段内,每一个<case>
字段都视为一个测试用例,case的属性assert用来表名该测试用例是正面例子还是反面例子,当assert值为true时,该测试用例是能匹配出漏洞的,而当assert为false时,该测试用例是没有漏洞的,而属性remark只是一个备注:
比较遗憾的是,我并没有找到直接在规则文件中测试测试用例的方法,希望Cobra在更新文档后能够对此进行说明。
author字段
这是Cobra提供的最后一个字段,用来标明该规则编写的作者是谁,毕竟辛苦编写了规则,那就署上你的大名吧:
规则文件命名
规则文件的命名规则:
- 统一存放在rules目录
- 大写字母CVI(Cobra Vulnerability ID)开头,横杠(-)分割
- 六位数字组成,前三位为Label ID,后三位为自增ID
- 结尾以小写.xml结束
例子:rules/CVI-110001.xml
值得注意的是,六位数字的前三位代表了漏洞类型,比如上文中我的规则文件命名为CVI-110003.xml,开头为110,因此被分到了“错误的配置”这一类。
具体的漏洞类别分类与定制详见:Cobra漏洞命名分类。
编写Rpo攻击漏洞规则
rpo攻击
rpo攻击是一种因为相对路径调用资源文件而产生的漏洞,详细见:rpo攻击浅析。
编写规则文件
由于rpo攻击属于xss攻击的一种,因此我把规则文件的名称设置成了CVE-140006.xml。规则的目的是匹配php中的使用相对路径调用js文件的语句,将其视为漏洞,提醒开发人员rpo攻击的可能性。具体规则如下:
<?xml version="1.0" encoding="UTF-8"?>
<cobra document="https://github.com/FeeiCN/cobra">
<name value="相对路径可能导致的rpo攻击漏洞"/>
<language value="php"/>
<match mode="regex-only-match">
<![CDATA[<script(\s)+(.)*src(\s)*=(\s)*"[^/\/{](.)*\.js"(\s)*>(\s)*(.)*(\s)*(</script>)]]>
</match>
<repair block="in-current-line">
<![CDATA[<script(\s)+(.)*src(\s)*=(\s)*"(http://|https://)(.)*\.js"(\s)*>(\s)*(.)*(\s)*(</script>)]]>
</repair>
<level value="3"/>
<solution>
## 安全风险
js对资源进行引用时采用了相对路径,即有可能导致rpo攻击漏洞
## 修复方案
使用绝对路径访问资源
</solution>
<test>
<case assert="true"><![CDATA[
<script src = "static/js/jquery.min.js"></script>
]]></case>
</test>
<test>
<case assert="false"><![CDATA[
<script src = "/static/js/jquery.min.js"></script>
]]></case>
</test>
<test>
<case assert="false"><![CDATA[
<script src = "http://1.1.1.1/static/js/jquery.min.js"></script>
]]></case>
</test>
<status value="on"/>
<author name="whiterabbit" email="whiterabbit@qq.com"/>
</cobra>
测试结果
测试结果图:
其他
附上Cobra官方中文文档连接:Cobra中文文档。