{
"id": "typo3",
"info": {
"name": "typo3",
"author": "your-name",
"tags": "detect,tech,typo3",
"severity": "info",
"metadata": {
"product": "typo3",
"vendor": "typo3",
"verified": false
}
},
"http": [
{
"method": "GET",
"path": ["/"],
"matchers": [
{
"type": "word",
"words": [
"<meta name="generator" content="TYPO3 CMS"",
"This website is powered by TYPO3"
],
"case-insensitive": false
},
{
"type": "word",
"words": [
"typo3conf/",
"typo3temp/"
],
"case-insensitive": true
},
{
"type": "regex",
"regex": [
"(?mi)<!--\s*TYPO3"
]
}
]
},
{
"method": "GET",
"path": ["/typo3/"],
"matchers": [
{
"type": "word",
"words": [
"TYPO3 CMS Login",
"typo3-login"
],
"case-insensitive": true
}
]
}
]
} 就以这个为例你能解释一下其中的各个参数吗
────
Thought for 2s (ctrl+o to expand)

● 好的,我逐层拆解这个 JSON 的每一个字段,从外到内解释。


第一层:根结构

{
"id": "typo3",
"info": { ... },
"http": [ ... ]
}

┌──────┬────────┬──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 字段 │ 类型 │ 作用 │
├──────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ id │ string │ 指纹的唯一标识符,不能和其他条目重复。引擎内部用它去重、索引。通常和 name 保持一致 │
├──────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ info │ object │ 元数据区,描述 "这是谁"—— 不参与匹配,只用于分类、搜索、展示结果 │
├──────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ http │ array │ 匹配规则区,核心部分。每个元素是一个 HTTP │
│ │ │ 请求 + 匹配规则;引擎逐个发送请求,只要任一元素的规则全部命中就算匹配成功 │
└──────┴────────┴──────────────────────────────────────────────────────────────────────────────────────────────────┘


第二层:info 元数据

"info": {
"name": "typo3",
"author": "your-name",
"tags": "detect,tech,typo3",
"severity": "info",
"metadata": {
"product": "typo3",
"vendor": "typo3",
"verified": false
}
}

info 各字段

┌──────────┬────────┬──────────────────────────────────────────────────────────────────────────────────────────────┐
│ 字段 │ 类型 │ 含义 │
├──────────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
│ name │ string │ 指纹显示名称,扫描结果里展示的就是这个 │
├──────────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
│ author │ string │ 作者署名,用于溯源 │
├──────────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
│ tags │ string │ 逗号分隔的标签,用于分类过滤。detect 表示这是个探测型指纹,tech 表示技术栈识别。你可以用 │
│ │ │ observer -tags detect,typo3 只跑特定标签 │
├──────────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
│ severity │ string │ 严重级别。这里写 info 因为只是资产识别,不是漏洞;如果是指纹某个漏洞版本才会写 │
│ │ │ critical/high/medium/low │
├──────────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
│ metadata │ object │ 扩展元数据,里面是键值对,字段自由定义 │
└──────────┴────────┴──────────────────────────────────────────────────────────────────────────────────────────────┘

metadata 各字段

┌──────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 字段 │ 含义 │
├──────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ product │ 产品名,标准化命名,方便和其他工具联动 │
├──────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ vendor │ 厂商名 │
├──────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ verified │ 重要 ——true 表示这个指纹经过人工验证确认可用;false │
│ │ 表示未验证(你自己刚写的)。提交到社区库前应该验证后改成 true │
└──────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────┘

▎ 💡 metadata 里还可以加 fofa-query、shodan-query 等字段,像库里那些条目一样,方便交叉搜索。


第三层:http 数组

"http": [
{
"method": "GET",
"path": ["/"],
"matchers": [ ... ]
},
{
"method": "GET",
"path": ["/typo3/"],
"matchers": [ ... ]
}
]

为什么是数组?

一个目标可能需要多个请求才能确认。比如:

  • 先请求首页,检查 HTML 关键字

  • 再请求后台路径,检查登录页特征

    触发逻辑:数组中每个元素是一个 "请求块"。引擎依次(或并发)发送请求,每个请求块的 matchers
    全部命中,该请求块才算匹配。整个指纹的匹配逻辑是 —— 任何一个请求块命中,就算识别成功。

    这相当于:请求块之间是 OR 关系,请求块内部的 matchers 之间是 AND 关系。

    每个请求块的字段

    ┌──────────┬────────┬──────────────────────────────────────────────────────────────────────────────────────────────┐
    │ 字段 │ 类型 │ 含义 │
    ├──────────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
    │ method │ string │ HTTP 方法:GET / POST / PUT 等。绝大多数指纹用 GET,因为我们是去 "看" 页面,不是改数据 │
    ├──────────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
    │ │ │ 请求路径列表。 │
    │ path │ array │ 是变量占位符,引擎会自动替换成用户输入的目标地址。数组意味着会尝试多个路径,比如 ["/", │
    │ │ │ "/typo3/"] 会先试首页再试后台 │
    ├──────────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
    │ matchers │ array │ 匹配规则集,见下文 │
    └──────────┴────────┴──────────────────────────────────────────────────────────────────────────────────────────────┘


    第四层:matchers 匹配规则

    这是指纹的核心 —— 回答 "打到响应后,怎么判断它是不是 TYPO3"。

    规则 1:精确关键字匹配

    {

    "type": "word",
    "words": [
        "<meta name=\"generator\" content=\"TYPO3 CMS\"",
        "This website is powered by TYPO3"
    ],
    "case-insensitive": false
    

    }

    ┌──────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────┐
    │ 字段 │ 含义 │
    ├──────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
    │ type: "word" │ 关键字匹配。引擎在响应体(HTML)中搜索这些字符串 │
    ├──────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
    │ words │ 关键字列表。数组内是 OR 关系 —— 命中任意一个即匹配。这里两条都指向 TYPO3:第一条是标准 meta │
    │ │ 标签;第二条是默认页脚的版权声明 │
    ├──────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
    │ case-insensitive: │ 区分大小写。TYPO3 官方写死了 TYPO3 CMS 这个大小写格式,所以用精确匹配能降低误报。如果写 │
    │ false │ true,"typo3 cms" 也能命中,但误报率会稍高 │
    └──────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────┘

    ▎ 🔑 为什么用两条? TYPO3 不同模板可能隐藏 meta 但保留页脚,反之亦然。拆成 OR 覆盖更多场景。

    规则 2:路径特征匹配

    {

    "type": "word",
    "words": [
        "typo3conf/",
        "typo3temp/"
    ],
    "case-insensitive": true
    

    }

    ┌─────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────┐
    │ 特点 │ 说明 │
    ├─────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
    │ case-insensitive: │ URL 路径在不同服务器上可能有大小写差异,所以忽略大小写更稳健 │
    │ true │ │
    ├─────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
    │ 为什么选这两个路径 │ typo3conf/ 是 TYPO3 的配置目录,typo3temp/ 是临时文件目录 —— 这两个目录是 TYPO3 │
    │ │ 架构独有的,其他 CMS 不会用这种命名规范。它们会出现在 CSS/JS 引用或图片链接中 │
    ├─────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
    │ 没有 condition │ 默认是 OR,命中任意一个即匹配 │
    └─────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────┘

    规则 3:正则匹配(HTML 注释)

    {

    "type": "regex",
    "regex": [
        "(?mi)<!--\\s*TYPO3"
    ],
    "case-insensitive": true
    

    }

    ┌────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────┐
    │ 字段 │ 含义 │
    ├────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤
    │ type: "regex" │ 正则表达式匹配,比 word 更灵活 │
    ├────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤
    │ regex │ 正则数组,同样是 OR 关系 │
    ├────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤
    │ │ 正则分解:<br>・(?mi) = 多行模式 + 忽略大小写 < br>・<!-- = HTML 注释开头 < br>・\s* = │
    │ (?mi)<!--\s*TYPO3 │ 零或多个空白符 < br>・TYPO3 = 注释内出现 TYPO3<br><br>TYPO3 经常在 HTML 源码里留下 <!-- │
    │ │ TYPO3SEARCH_begin --> 或 <!-- This website is powered by TYPO3 --> 等注释 │
    └────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────┘

    没有出现的 condition 字段

    库里有些规则是这样的:

    {

    "type": "word",
    "words": ["name=\"dede_fields", "name=\"dede_fieldshash"],
    "condition": "and",
    "case-insensitive": true
    

    }

    condition 有两种值:

  • 不写 / "or":words 数组里命中任意一个就算匹配(宽松)

  • "and":words 数组里全部都要命中才算匹配(严格)

    ▎ 🔑 什么时候用 and? 当单独一个词太常见(如 "admin"),误报率高,但多个词同时出现就能唯一确定目标时。比如同时出现
    ▎ dede_fields 和 dede_fieldshash 才能确认是 DedeCMS。


    第二个请求块

    {

    "method": "GET",
    "path": ["{{BaseURL}}/typo3/"],
    "matchers": [
        {
            "type": "word",
            "words": ["TYPO3 CMS Login", "typo3-login"],
            "case-insensitive": true
        }
    ]
    

    }

    ┌─────────────────┬────────────────────────────────┐
    │ 要点 │ 说明 │
    ├─────────────────┼────────────────────────────────┤
    │ 路径 /typo3/ │ TYPO3 后台登录的默认路径 │
    ├─────────────────┼────────────────────────────────┤
    │ TYPO3 CMS Login │ 登录页标题 / 标题栏常见文案 │
    ├─────────────────┼────────────────────────────────┤
    │ typo3-login │ 登录表单的 CSS class,非常独特 │
    └─────────────────┴────────────────────────────────┘

    这个请求块的意义是:即使首页被大幅定制找不到特征,后台登录页的路径和文案几乎不会被改动,相当于一个兜底检测。


    整体匹配逻辑总结

    ┌─ 请求块 1: GET /
    │ ├─ 规则 1: word ── 命中 "meta...TYPO3 CMS" 或 "powered by TYPO3" ← OR
    │ ├─ 规则 2: word ── 命中 "typo3conf/" 或 "typo3temp/" ← OR
    │ └─ 规则 3: regex ─ 命中 /<!--\s*TYPO3/ ← AND (规则之间)
    │ → 三条规则全部通过 → 请求块 1 命中 ✅

    └─ 请求块 2: GET /typo3/

    └─ 规则1: word ── 命中 "TYPO3 CMS Login" 或 "typo3-login"            ← 单条规则
        → 规则通过 → 请求块2 命中 ✅
    

    │ 要点 │ 说明 │
    ├─────────────────┼────────────────────────────────┤
    │ 路径 /typo3/ │ TYPO3 后台登录的默认路径 │
    ├─────────────────┼────────────────────────────────┤
    │ TYPO3 CMS Login │ 登录页标题 / 标题栏常见文案 │
    ├─────────────────┼────────────────────────────────┤
    │ typo3-login │ 登录表单的 CSS class,非常独特 │
    └─────────────────┴────────────────────────────────┘

    这个请求块的意义是:即使首页被大幅定制找不到特征,后台登录页的路径和文案几乎不会被改动,相当于一个兜底检测。


    整体匹配逻辑总结

    ┌─ 请求块 1: GET /
    │ ├─ 规则 1: word ── 命中 "meta...TYPO3 CMS" 或 "powered by TYPO3" ← OR
    │ ├─ 规则 2: word ── 命中 "typo3conf/" 或 "typo3temp/" ← OR
    │ └─ 规则 3: regex ─ 命中 /<!--\s*TYPO3/ ← AND (规则之间)
    │ → 三条规则全部通过 → 请求块 1 命中 ✅

    └─ 请求块 2: GET /typo3/

    └─ 规则1: word ── 命中 "TYPO3 CMS Login" 或 "typo3-login"            ← 单条规则
        → 规则通过 → 请求块2 命中 ✅
    

    请求块 1 命中 OR 请求块 2 命中 → 输出: "检测到 TYPO3"

    用伪代码表示:

    def match(response_list):

    for http_block in fingerprint["http"]:
        response = send_request(http_block["method"], http_block["path"])
        block_matched = True
        for matcher in http_block["matchers"]:
            if not evaluate(matcher, response):
                block_matched = False
                break  # 该请求块失败,跳到下一个请求块
        if block_matched:
            return True  # 指纹命中
    return False  # 所有请求块都不匹配
    

    关键记住三句话:

  • matchers 之间是 AND(全部规则通过才算)

  • words/regex 数组内是 OR(命中一个即可)

  • http 数组之间是 OR(任何一个请求块命中就识别成功)

    这样就构建了一个既灵敏又抗误报的指纹规则。

更新于

请我喝[茶]~( ̄▽ ̄)~*

Suxinal 微信支付

微信支付

Suxinal 支付宝

支付宝

Suxinal 贝宝

贝宝