一、背景
二、概述
三、逻辑流程
四、部分流程
1、CodeQL构造Source的访问URL
2、入口程序运行CodeQL查询
3、中转程序构造请求包发送到XRay
4、XRay黑盒扫描并发送到webhook
5、webhook示例
6、最终的输出
五、测试数据
六、概括一下
1、笔者在一个甲方公司
2、最近在学习CodeQL
3、我们公司约等于只有我一个安全测试
4、需要测试的系统很多
白盒扫描器的优点是可以覆盖更多的漏洞点,但是精确率相对较低,需要较多人力进行校验。
黑盒扫描器的优点是精确率更高,但是覆盖的漏洞点相对较低,需要更多的流量增加覆盖度。
结合两者的优点可以在覆盖到更多的漏洞点的同时又能节省到人力,而且还可以解决黑盒扫描器所需的流量问题。
最终的漏洞事件将合并白盒的扫描结果以及黑盒的扫描结果,若某个事件在白盒中认为是漏洞,但是在黑盒中不认为是漏洞则将该事件的可信度设置为中,若某个事件同时在白盒和黑盒中认为是漏洞则将事件的可信度设置为高。
我测试了多个公司的项目,因为可信度为高的事件精确率总是100%,所以可信度为高的事件可以跳过人工复查直接入到漏洞运营的环节。
如下以CodeQL与黑盒扫描器XRay为例,简单描述一下整个过程。
CodeQL入门文章可以看:CodeQL快速上手
CodeQL根据扫描结果中的Source构造出入口URL,并标记漏洞参数,然后通过中转程序转发到黑盒扫描工具进行二次验证,用来增加扫描结果的可信度,不同等级的可信度做不同的处理,针对高可信的漏洞可以自动进入漏洞运营的环节。
以我们公司用的SSM框架,扫描反射型XSS漏洞为例
在CodeQL中根据source所在位置构造出入口URL
说一下组装参数部分,这个环节需要解决如下几个问题:
1、参数名与URL里面的参数不一致的情况
从URL中接收的参数是id,但是在方法里面使用的参数是empId
针对这种情况,我在获得方法中的形参时会先判断该参数是否使用了RequestParam标注,如果有则用该标注中value参数的值替换标记这个参数。
2、在方法体里面利用request.getParameter传参的情况
我在CodeQL中定义了两个获取参数的谓词,一个获取方法中的参数,一个获取方法体中的参数。
3、在子方法中调用参数的情况
针对这种情况,我加了一个污点追踪,获取到子方法中映射参数的同时再将这个流程合并到父方法中。
4、映射的参数是封装的对象时
遇到这个情况的参数时,我会进入的这个类中,然后获取所有的字段,再进行赋值组装。
5、不同数据类型的赋值情况
常见的参数类型有数字类型、字符串类型、Date类型
Date类型的参数在从字符串转化过来的时候有些需要yyyy-MM-dd HH:mm:ss类型,有些需要yyyy/MM/dd HH:mm:ss类型
目前我只做了简单的方式进行容错,遇到Date类型的参数时生成2个URL,URL1中的Date参数使用格式1,URL2中的Date参数使用格式2,待优化。
6、某些参数的值必需要属于某个数值集合时
例如字符串类型的type参数,必需等于view或者edit;这个问题还没有想到好的解决办法,TODO了。
独立运行时示例如下
使用Python的subprocess模块执行CodeQL CLI的query查询,然后解析查询结果
在中转程序中可以组装出完整的URL,并装载Cookie的信息,发送HTTP请求到XRay
proxies = {"http":"http://127.0.0.1:7777",
"https":"https://127.0.0.1:7777"}
requests.get(url, headers=headers, cookies=cookies, proxies=proxies)
xray\_windows\_amd64.exe webscan --listen 127.0.0.1:7777 --plugins xss --webhook-output http://127.0.0.1:5000/webhook
会以POST方式JSON格式发送漏洞信息,示例如下
如下Demo以在控制台中打印自定义的漏洞信息为例。
运行程序,默认监听5000端口
可以在WebHook中将漏洞事件输出到数据库中,然后在WEB中进行呈现
测试了多个项目,以其中一个项目的数据为例,如下我是用漏洞接口作为的统计维度,毕竟统计起来相对省时间Emmm:
ALL表示所有的样本,是我仔细的人工审计的结果。
真漏洞接口表示这个接口存在漏洞,假漏洞接口表示这个接口不存在漏洞,但是存在输入输出,有些是因为使用了安全SDK进行编码,有些是其他原因导致的不存在漏洞。
若是仅仅依赖白盒扫描器的话,我们可以把规则写细致一点,宁缺毋滥,提高精确率,降低人工成本,但是可能会牺牲召回率。
若是同时使用黑盒扫描器的话,我们可以把规则放宽一点,提高召回率,但是可能会牺牲准确率,可以自行选择是否需要人工校验非高可信的事件。
测试了多个项目,CodeQL扫描的召回率全是100%,XRay的精确率全是100%,这两个属性应该是固定了。
有些参数接收了并且发送给了JSP文件中,但是在JSP中却没有使用,而且在JSP中也可能进行编码处理,所以会导致CodeQL的精确率低。
有些参数需要特定的值,有些参数需要特定的格式,所以会导致XRay的召回率低。
仁者见仁,公司的环境不同最佳方案就不同。
CodeQL的扫描结果通过中转脚本发送给黑盒扫描器,例如XRay,
若CodeQL产生的告警,同时在黑盒扫描器中扫描出漏洞,则可以将这个事件定义的可信程度定义为:高;
若CodeQL产生的告警,在黑盒扫描器中未扫描出漏洞,则可以将这个事件定义的可信程度定义为:中。
高可信的事件,直接发送到漏洞运营平台生成漏洞工单,其他的事件,记录在漏洞运营系统的白盒扫描模块,等待安全工程师二次确认。
在黑盒扫描器环节最好还是自研,因为在这个流程中关键参数已经被标记了,无需再尝试所有的参数,而XRay无法限定待扫描的参数,所以会发送更多的请求包。