Skip to main content

相关定义

被动指纹(Passive)

  • 不请求: 不写request结构
  • / 请求, 无其它额外设置
request:
  cache: true
  method: GET
  path: /
  • icon: 使用 getIconContent 函数

主动指纹(Active)

除被动指纹外的情况都属于主动指纹

编写规范(Prepare a specification)

目前 lint 会检查以下内容
  1. celcheck:用于校验 cel 语句是否能够运行,类型推到的结果是否正确。
  2. schemacheck:校验脚本内容是否符合编写的 json schema 格式,用于检测是否有必须填写的字段缺失。
  3. payloadcheck:检查每一个 payload 分支内声明的变量类型是否是一致的。
  4. transportcheck:校验 rule 中的请求是否符合规范。
  5. 相关细节以及对应修复方式请参考YAML插件修复手册
当存在多个‘或’逻辑的时候,系统会按序执行,直到命中一个才会停止,所以,将常命中的规则放在越靠前的位置能够有效的减少不必要的发包
被动指纹指的是只向根路径发包,或者只使用获取icon的函数进行指纹识别的指纹,而除了这两种情况,其他的都属于主动指纹。
例如匹配discuz的时候,关键词中最好带有该产品的特殊的内容,例如discuz_uid等。 特别的:部分通用系统存在二次开发修改title的情况,因此title只能作为辅助判断的逻辑,只能算作加强规则,不能作为决定性证据
一般来讲,符合第四点的情况下,两条规则即可
一般有两种情况,一种是spring的访问/env等路径,有些时候会被拦;一种情况是path中带有admin,有些waf会拦截
icontains在匹配时会忽略匹配字母的大小写,增加资源消耗
get404Path函数做了一些特殊处理,这个函数可以保证一个目标将仅拥有一个404path,这样便于使用cache,降低发包,提高效率。
getIconContent函数可以在响应中获取icon地址,然后访问这个icon获取其字节流数据。
例如:kw_in_body_01、kw_in_body_02
详情参考:三目运算符的使用方式
name: fingerprint-yaml-tcp-mysql
manual: false
transport: tcp
set:
  GenericLines: b"\r\n\r\n"
payloads:
  payloads:
    l:
      re: '"(?s)^.\\0\\0\\0\\xffj\\x04''[\\d.]+'' .* MySQL"'
    m:
      re: '"(?s)^.\\0\\0\\0\\x0a(?P<version>5\\.[-_~.+:\\w]+MariaDB-[-_~.+:\\w]+~bionic)\\0"'
    n:
      re: '"(?s)^.\\0\\0\\0\\x0a(?P<version>[\\w._-]+)\\0............\\0\\x5f\\xd3\\x2d\\x02\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0............\\0$"'
    r:
      re: '"(?s)^.\\0\\0\\0\\x0a(?P<version>3\\.[-_~.+\\w]+)\\0...\\0"'
    s:
      re: '"(?s)^.\\0\\0\\0\\x0a(?P<version>4\\.[-_~.+\\w]+)\\0"'
rules:
  r1:
    request:
      cache: true
      content: '{{GenericLines}}'
    expression: re.bmatches(response.raw)
    output:
      result: re.bsubmatch(response.raw)
      osname: |
        re.contains("bionic") ? "Linux" : ""
      version: result["version"]
expression: r1()
detail:
  fingerprint:
    infos:
      - type: system_bin
        name: mysql
        version: '{{version}}'
      - type: operating_system
        name: '{{osname}}'

通过 ICON HASH 匹配

建议规则名称:favicon_hash

便捷计算icon hash的方式

  • Windows
  • Linux
将下列代码放入powershell中运行,请确保你对应版本的python有安装requests,mmh3包
function Get-IconHash {
param(
    [string]$url
)
python -c "import requests,sys,mmh3,codecs;print('icon_hash=' + str(mmh3.hash(codecs.lookup('base64').encode(requests.get('$url').content)[0])))"
}
使用示例:
Get-IconHash 'https://www.baidu.com/favicon.ico'

# 运行结果
icon_hash=-1588080585

使用内置函数自动搜索 ICON 路径

rules:
  favicon_hash:
    request:
      method: GET
      path: /
    expression: |-
      faviconHash(response.getIconContent()) == 149371702

自定义 ICON 路径

rules:
  favicon_hash:
    request:
      method: GET
      path: /not_normal_favicon_path.ico
    expression: |-
      faviconHash(response.body) == 149371702

通过内容MD5匹配

建议规则名称:md5_in_[position]
rules:
  md5_in_body:
    request:
      method: GET
      path: /this_is_test_path
    expression: |-
      md5(response.body) == "ce1a1c8754948c6cbfcfa48545e8174b"

通过 Body 关键字匹配

建议规则名称:kw_in_body

基础模版(Basic templates)

rules:
  kw_in_body:
    request:
      method: GET
      path: /
    expression: |-
      response.body_string.contains("<hr><center>openresty")

匹配的字符串中包含引号(inverted comma)

rules:
  kw_in_body:
    request:
      method: GET
      path: /
    expression: |-
      response.body_string.contains('href="https://www.cloudflare.com/5xx-error-landing"')

忽略大小写(ignore capitals)

rules:
  kw_in_body:
    request:
      method: GET
      path: /
    expression: |-
      response.body_string.icontains('seeyon')

二进制内容匹配(binary)

rules:
  kw_in_body:
    request:
      method: GET
      path: /
    expression: |-
      response.body.bcontains(b'\xe6\x98\x93\xe7\xbd\x91\xe5\x85\xb3')

通过 Header 关键字匹配

建议规则名称:kw_in_header || kw_in_[header_name]
rules:
  kw_in_cookie:
    request:
      method: GET
      path: /
    expression: |-
      response.headers["Cookie"].contains("JSESSIONID=")

Server 匹配

rules:
  kw_in_server:
    request:
      method: GET
      path: /
    expression: |-
      response.headers["server"].contains("Apache/")

不常见的 Header Key 匹配(规则名称统一使用 kw_in_header)

rules:
  kw_in_header:
    request:
      method: GET
      path: /
    expression: |-
      response.headers["X-Protected-By"].contains("OpenRASP")

判断某个 Key 是否在 Headers 中

rules:
  kw_in_header:
    request:
      method: GET
      path: /
    expression: |-
      "CF-RAY" in response.headers

在完整响应头中匹配(raw_header)

rules:
  kw_in_header:
    request:
      method: GET
      path: /
    expression: |-
      response.raw_header.bcontains(b'HP-ChaiSOE')

通过 CERT 关键字匹配

建议规则名称:kw_in_cert
rules:
  kw_in_cert:
    request:
      method: GET
      path: /
    expression: |-
      response.raw_cert.ibcontains(b"SANGFOR VMP")

通过 404Path 进行特征匹配

name: xxxxx
transport: http
detail:
  cpe: xxxx
set:
  pathname: get404Path()
rules:
  kw_in_404_body:
    request:
      method: GET
      path: /{{pathname}}
    expression: response.body_string.contains("xxxx")
expression: kw_in_404_body()

多个 Context 匹配的简化写法

name: hessian
transport: http
detail:
  cpe: caucho_technology:hessian
  version: '{{version}}'
payloads:
  payloads:
    p0:
      path: |
        "<path_0>"
    p1:
      path: |
        "<path_1>"
    p2:
      path: |
        "<path_2>"
rules:
  kw_in_body:
    request:
      method: POST
      path: /{{path}}
    expression: |
      response.body_string.contains("xxx")
expression: kw_in_body()

使用正则表达式进行匹配(RE)

rules:
  kw_in_body:
    request:
      method: GET
      path: /
    expression: |-
      "/owa/auth/.*?/themes/resources/favicon.ico".matches(response.body_string)

使用正则提取信息(RE)

version_detect:
  request:
    method: GET
    path: /
  expression: |
    "server" in response.headers && response.headers["server"].contains("nginx")
  output:
    version: |
      "^nginx/(?P<version>.*)$".submatch(response.headers["server"])["version"]
I