Skip to main content

EZ 指纹开发

1.前言

EZ的指纹和POC编写评价体系主要依赖于两个指标:精确率(precision)和召回率(accuracy)。

精确率是针对我们预测结果而言的,它表示的是预测为正的样本中有多少是真正的正样本。 召回率是针对我们原来的样本而言的,它表示的是样本中的正例有多少被预测正确了。

通俗来讲,精确率就是匹配出来的结果准不准确?有多少误报,误报越高,精确率就越低。而召回率是评价有多少本应该匹配出来的结果被漏掉了,召回率越高,漏掉的越少,漏报率越低。所以,理想情况下,我们编写的最佳POC精确率和召回率都应当是100% . 当然,这样的理想情况不太可能达到,但是我们需要想办法让它无限趋近于100% .

2.指纹开发

下面我们先来谈一下EZ的指纹开发。所谓指纹就是一款应用(大多数情况下是Web应用)所具有的独有的特征,根据该特征,我们就可以识别出这款应用的通用框架或组件等。 举个例子:Discuz是一款由康盛公司开发的知名论坛类型的CMS系统。它的外观通常是这样的:

但也有可能是这样的:

从外观上看,两个网站有很大区别,几乎不是同一个类型的。但是,我们可以去找共同点,这个过程也就是指纹提取。 指纹提取,通常需要我们查看网页源码,我们来看一下二者源码有什么相同点:

注意到: <meta name="generator" content="Discuz! X3.?" />这一行。其中,第一个网站是3.1,而第二个网站是3.3 。这个指纹通常是不会被改变的。 于是一条识别Discuz框架的指纹就产生了,那就是: 源码含有<meta name="generator" content="Discuz!

EZ目前支持的指纹规则特征有:

  1. 首页源码
  2. 首页header
  3. 图标hash
  4. 静态文件内容
  5. 静态文件hash

下面我们分别来介绍一下:

1.首页源码,首页就是指服务器根目录。例如 http://www.ez.com/ 这个页面。需要注意的是:如果访问该页面存在跳转的话,需要看该跳转是属于301、302跳转还是通过页面中的JS控制的跳转。目前EZ仅支持301和302场景的5次以内的跳转。如果跳转中出现了JS跳转或超过5次,则匹配以出现JS跳转时的页面内容或最后一次的HTTP Response中的HTML为主体。

2.首页header,可匹配首页响应中的Header内容,即如下图所示的一些头部字段:

3.图标hash 。 一些通用框架及组件可能会使用相同的图标,此时可以使用图标hash来匹配。如果使用图标,可以使用如下脚本计算hash:

import mmh3,sys,codecs,requests
url = "https://ez.com/favicon.ico"
r = requests.get(url,verify = False)
print(mmh3.hash(codecs.encode(r.content,"base64")))

使用过程中,需要将ez.com修改成目标网站的域名。

4.静态文件内容。匹配指定URL下的文件内容,由于需要额外发送1个请求,故不推荐使用该匹配方法。

5.静态文件hash。匹配指定URL下文件的hash,hash计算规则与图标hash一致,由于需要额外发送1个请求,故不推荐使用该匹配方法。

下面我们来评价一下前面我们采用的Discuz指纹。

首先,我们来看该指纹的精确率。从直观角度来说,大多数网站通常不会刻意在首页源码中加入 <meta name="generator" content="Discuz! 这样的信息,但有一种情况例外——蜜罐。蜜罐为了诱捕和伪装,可能会将自己首页源码中添加大量的开源CMS信息。在不考虑蜜罐这种特殊情况时,该指纹的精确率还是很高的,接近于100% 。

下面我们再来看一下召回率。对于一些二次开发的Discuz系统,开发人员可能会将该meta标签删除或将content修改为自身网站的标题或公司名称,这种情况下会导致一定的遗漏,召回率因此受到一定程度影响会有所下降。 粗略来讲,该指纹规则的精确率很高,而召回率略有不足。

下面我们用另一套指纹规则来匹配。 我们注意到,两个网站首页源码中都含有这样一段内容: name="srhlocality" 这段内容,可以说是Discuz系统所特有的,与其他系统的碰撞的可能性极低。我们以此为指纹,精确率仍然很高,接近于100% ,但召回率会得到显著提升。因为即使网站经过二次开发,有相当一部分网站仅会修改外观,而不会去修改这段处于表单中的内容。(因为一旦修改表单,后端的代码也需要修改。)

接下来我们利用fofa来量化一下这两组指纹的召回率。

打开fofa.so,分别输入: body="<meta name=\"generator\" content=\"Discuz!\"" body="name=\"srhlocality\""

如果把后者的召回率比作1的话,前者的召回率大概在99.10% 。这样看来二者是有些细微区别的,我们鼓励开发者尽可能多地尝试使用不含有框架本身信息的指纹,以避免在二次开发场景下的篡改,导致召回率下降。 下面我们再来看一下使用Discus默认图标hash作为指纹的检测情况。

通过运行脚本,我计算出Discuz默认图标的hash,这个hash在fofa也是通用的。下面我们在fofa检索该hash,使用语法: icon_hash="-505448917"

结果是74753条。说明,大约有30%的Discuz网站修改了默认的图标。因此,在这个规则匹配场景,不建议使用图标hash进行匹配。

下面我们再来看几个有代表性的指纹案例:

1.Node-RED 是一款IOT领域常用的开源工具。目前fofa已经具备该指纹,我们可以使用: app="nodered" 来进行检索。

通过查看源码,我们注意到,Node-Red web源码中加载了具有显著特征的一个JS文件: <script src="red&#x2F;red.min.js"></script> 我们以此为指纹,重新检索: body="red&#x2F;red.min.js"

发现匹配数量增加了500个,从增加的信息中我们看到:

fofa指纹:

我们的指纹:

虽然Node-RED标题的数量略有下降,但是我们额外匹配出了其他几种标题:

通过查看其中一个非Node-RED标题的网站内容我们发现,该网站仅仅是标题做了修改,其本身还是Node-Red系统。

证明该指纹能够提升一定的召回率,指纹属性优于fofa。

2.LanProxy 是一款开源内网穿透工具,其本身具有Web界面。

我们以LanProxy内网穿透 为关键词搜索该Web应用,发现数量仅有245条:

但是,我们发现,该应用的背景色具有显著特征:

以该背景色作为关键词进行搜索,可以检索出3000多条记录:

根据Server字段,我们又可以锁定2540条记录的返回头Server字段具体相同特征。

此时我们观察LanProxy的Server字段:

可以基本以该指纹锁定应用。

指纹内容为: 首页header匹配:LPS-0.1

有时,我们选取一个特殊独有的js或css文件名或一个特殊独有的color数值就可以将指纹的召回率提高到最高,然后再通过抽样检测判断精确率是否较高即可。若精确率不高,可以再次添加指纹来提高精确率。EZ支持多个指纹取交集来匹配。

还有一些场景,我们采用的任何一条指纹都无法将召回率达到70%以上,此时,我们需要针对该组件添加两条指纹,注意这两条指纹的名称需要保持一致。此时,两条指纹是取并集关系,可极大提升指纹的召回率。

理想情况下,我们当然希望开发者设计出的指纹精确率和召回率都是1。但事实上,做到二者兼顾会很难,由于漏洞检测从性质上属于负向质检项,所以应当保证召回率优先。在一定程度上可以牺牲精确率,牺牲精确率带来的代价是让EZ多发送额外的扫描请求,额外发送数量等于(1-精确率)* 该规则扫描请求总量。例如精确率达到80%,扫描器会额外发送20%不必要的请求。但是如果召回率降低(例如50%),就有一半的实际存在漏洞的场景无法扫描出来,这个后果是很严重的。

3. EZ自定义指纹功能

EZ支持通过 data/finger_custom.json 文件引入自定义指纹。

示例如下:

[
{
"product_name": "kingdee-eas",
"company": "金蝶",
"industry": "",
"level": 2,
"rules": {
"body": [
"服务器找不到请求的资源:&#x2F;</P>"
]
}
}
]

字段介绍:

product_name指纹名称。该名称对应于PoC插件中finger字段指定的名称,若EZ已有同类产品指纹,名称尽可能与原有名称保持一致
company组件生产厂商。要求填写准确,若不清楚可不填写
industry行业分类。要求填写准确,若不清楚可不填写
level参考PoC的风险等级设定
rulesbody(List,String): 根据响应体中的关键词匹配。如有多个关键词,可放置于同一个数组内,多个关键字会使用and关系匹配。
header(List,String): 根据响应头中的关键词匹配。如有多个关键词,可放置于同一个数组内,多个关键字会使用and关系匹配。
icon_hash(String):直接填写图标的fofa icon_hash值。

EZ 主动指纹规则编写 (EZ >= v1.9.3)

主动指纹规则开放,以便于完善检查一些特殊的指纹,比如shiro、nacos等。 编写规则格式与POC YAML规则一致,下面举例几个例子来说明

Examples

通过对data/finger.yaml进行编辑,可实现多个主动指纹规则定义。如果文件不存在,则新建文件。

shiro-detect

shiro规则一般是在请求头带一个rememberMe,然后判断返回的headers中set-cookie是否为deleteMe,如果包含的话说明是shiro框架

- name: shiro-detect
level: 0
rules:
- method: GET
follow_redirects: false
path: /
headers:
Cookie: rememberMe=1
expression: |
"set-cookie" in response.headers && response.headers["set-cookie"].contains("deleteMe")

nacos-detect

在探测nacos的时候,很多时候都是在/nacos目录,而/通常返回都是404。

- name: nacos
level: 0
rules:
- method: GET
follow_redirects: true
path: /nacos
expression: |
response.body.bcontains(b"<title>Nacos</title>")