指纹识别+精准化POC攻击

admin 2026-01-09 02:58:43 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文提出一种结合指纹识别与Nuclei实现精准化POC攻击的方案。文章详细解析了基于特定文件、页面关键字、请求头及URL路径的指纹识别技术,提供了基于EHole库的Python多线程识别代码。该方案通过识别目标指纹并匹配Nuclei模板标签,自动执行针对性漏洞扫描,有效解决了传统扫描器检测量大且效率低的问题。 综合评分: 88 文章分类: 渗透测试,安全工具,WEB安全,漏洞分析,红队


指纹识别+精准化%20POC%20攻击

蚁景网安

2026年1月8日%2016:46 湖南

以下文章来源于蚁景网络安全 ,作者lll

蚁景网络安全 .

致力于为你带来更实用的网络安全技术内容!

开发目的

解决漏洞扫描器的痛点

第一就是扫描量太大,对一个站点扫描了大量的无用%20POC,浪费时间

指纹识别后还需要根据对应的指纹去进行%20payload%20扫描,非常的麻烦

开发思路

我们的思路大体分为指纹+POC+扫描

所以思路大概从这几个方面入手

首先就是%20POC,我们得寻找一直在更新的%20POC,而且是实时更新的,因为自己写的话有点太费时间了

但是这%20POC%20的决定是根据我们扫描器来的,因为世面上已经有许多不错的扫描器了,目前打算使用的是%20nuclei%20扫描器

https://github.com/projectdiscovery/nuclei

Nuclei%20是一种现代、高性能的漏洞扫描程序,它利用基于%20YAML%20的简单模板。它使您能够设计自定义漏洞检测场景,以模拟真实世界的条件,从而实现零误报。

目前也在不断维护更新,当然还有%20Xray,Goby%20等工具也是不错的选择

然后回到指纹识别技术,这个需要大量的指纹样本,但是世面上的各种工具已经可以做得很好了

指纹识别

这里就的学习一下指纹识别的技术

首先我们需要知道收集指纹目前大概有哪些方法

指纹识别方式 特定文件

比如举一个例子,我们通常是如何判断一个框架是%20thinkphp%20呢?

我们随便找几个%20thinkphp%20的网站

特征就是它的图标是非常明显的

可以看到图标都是一样的,目前%20fofa%20和%20hunter%20已经有这种查找的方法了,一般都是把我们的图标换算为我们的%20hash%20值

这个就是我们的%20favicon.ico%20图标

一般网站是通过在路径后加入%20favicon.ico%20比如 http://xxxxxx/favicon.ico

然后就能获取这个图标了,而在%20fofa%20中可以直接拖动查询了,可以直接算出%20hash%20值

比如%20thinkphp%20的

然后再次查询

全是%20tp%20的网站 参考https://github.com/TideSec/TideFinger/blob/master/Web%E6%8C%87%E7%BA%B9%E8%AF%86%E5%88%AB%E6%8A%80%E6%9C%AF%E7%A0%94%E7%A9%B6%E4%B8%8E%E4%BC%98%E5%8C%96%E5%AE%9E%E7%8E%B0.md

当然除了我们的%20ico%20文件,还有其他很多的文件

一些网站的特定图片文件、js%20文件、CSS%20等静态文件,如%20favicon.ico、css、logo.ico、js%20等文件一般不会修改,通过爬虫对这些文件进行抓取并比对%20md5%20值,如果和规则库中的%20Md5%20一致则说明是同一%20CMS。这种方式速度比较快,误报率相对低一些,但也不排除有些二次开发的%20CMS%20会修改这些文件。

页面关键字

比如%20tp%20的错误页面大多数都是

我们%20body%20就可以包含这个关键字了

或者可以构造错误页面,根据报错信息来判断使用的%20CMS%20或者中间件信息,比较常见的如%20tomcat%20和%20spring%20的报错页面。 根据%20response%20header%20一般有以下几种识别方式:

请求头关键字

根据网站%20response%20返回头信息进行关键字匹配,这个一般是%20ningx%20这种

能够识别我们的服务器

URL%20路径

根据总结 wordpress%20默认存在%20wp-includes%20和%20wp-admin%20目录,织梦默认管理后台为%20dede%20目录,solr%20平台可能使用/solr%20目录,weblogic%20可能使用%20wls-wsat%20目录等。

大部分还是根据我们的%20body

然后点一个进去

可以看到都是我们的%20wordPress%20的站点

指纹识别方法

有了我们上面的识别技术,那么我们大概是如何来识别一个指纹的呢

首先使用%20python%20简单举一个实现

首先就是需要一个配置文件,这个配置文件就需要包含我们的大体指纹和验证方法

-%20name:%20ThinkPHP
matchers:
 %20-%20type:%20header
 %20 %20rule:%20X-Powered-By
 %20 %20keyword:%20ThinkPHP

 %20-%20type:%20body
 %20 %20keyword: "http://www.thinkphp.cn"

 %20-%20type:%20banner
 %20 %20keyword:%20thinkphp

 %20-%20type:%20path
 %20 %20path:%20/thinkphp/library/think/
 %20 %20keyword: class

 %20- type: favicon_hash
 %20  hash:%201165838194

然后就是我们的后端处理逻辑了

import%20yaml
import%20requests
import%20socket
import%20base64
import%20mmh3

def get_http_response(url,%20path=""):
 %20  try:
 %20 %20 %20 %20full_url%20=%20url.rstrip("/")%20+%20path
 %20 %20 %20  return requests.get(full_url,%20timeout=5)
 %20 %20except:
 %20 %20 %20  return None

def get_tcp_banner(ip,%20port=80):
 %20  try:
 %20 %20 %20 %20with%20socket.create_connection((ip,%20port),%20timeout=5) as s:
 %20 %20 %20 %20 %20 %20banner%20=%20s.recv(1024).decode(errors="ignore")
 %20 %20 %20 %20 %20  return banner
 %20 %20except:
 %20 %20 %20  return""

def get_favicon_hash(url):
 %20  try:
 %20 %20 %20 %20res%20=%20requests.get(url.rstrip("/")%20+ "/favicon.ico",%20timeout=5)
 %20 %20 %20 %20favicon%20=%20base64.encodebytes(res.content)
 %20 %20 %20  return mmh3.hash(favicon.decode('utf-8'))
 %20 %20except:
 %20 %20 %20  return None

def load_fingerprints(path="fingerprints.yaml"):
 %20 %20with open(path, "r",%20encoding="utf-8") as f:
 %20 %20 %20  return yaml.safe_load(f)

def match_fingerprint(url,%20ip=None):
 %20 %20fingerprints%20= load_fingerprints()
 %20 %20results%20=%20[]

 %20 %20res%20= get_http_response(url)
 %20 %20banner%20= get_tcp_banner(ip or url.replace("http://", "").replace("https://", ""), 80)
 %20 %20favicon_hash%20= get_favicon_hash(url)

 %20  for fp%20in%20fingerprints:
 %20 %20 %20 %20matched%20=%20False
 %20 %20 %20  for matcher%20in%20fp["matchers"]:
 %20 %20 %20 %20 %20  if matcher["type"]%20== "header"and res:
 %20 %20 %20 %20 %20 %20 %20  if matcher["rule"]%20in%20res.headers and matcher["keyword"].lower()%20in%20res.headers[matcher["rule"]].lower():
 %20 %20 %20 %20 %20 %20 %20 %20 %20 %20matched%20=%20True
 %20 %20 %20 %20 %20 %20elif%20matcher["type"]%20== "body"and res:
 %20 %20 %20 %20 %20 %20 %20  if matcher["keyword"].lower()%20in%20res.text.lower():
 %20 %20 %20 %20 %20 %20 %20 %20 %20 %20matched%20=%20True
 %20 %20 %20 %20 %20 %20elif%20matcher["type"]%20== "banner":
 %20 %20 %20 %20 %20 %20 %20  if matcher["keyword"].lower()%20in%20banner.lower():
 %20 %20 %20 %20 %20 %20 %20 %20 %20 %20matched%20=%20True
 %20 %20 %20 %20 %20 %20elif%20matcher["type"]%20== "path":
 %20 %20 %20 %20 %20 %20 %20 %20res2%20= get_http_response(url,%20matcher["path"])
 %20 %20 %20 %20 %20 %20 %20  if res2 and matcher["keyword"].lower()%20in%20res2.text.lower():
 %20 %20 %20 %20 %20 %20 %20 %20 %20 %20matched%20=%20True
 %20 %20 %20 %20 %20 %20elif%20matcher["type"]%20== "favicon_hash":
 %20 %20 %20 %20 %20 %20 %20  if favicon_hash%20==%20matcher["hash"]:
 %20 %20 %20 %20 %20 %20 %20 %20 %20 %20matched%20=%20True
 %20 %20 %20  if matched:
 %20 %20 %20 %20 %20 %20results.append(fp["name"])
 %20  return results

#%20示例使用
if __name__%20== "__main__":
 %20 %20target_url%20= "http://101.200.50.94:8009/"
 %20 %20result%20= match_fingerprint(target_url)
 %20  print("识别结果:",%20result)

大体逻辑就是这样了

首先就是%20yaml%20文件为我们的判断依据,对应不同的判断方法我们都有对应的后端处理

一个是对%20body%20的处理,一个是对%20hash%20文件的处理

然后再根据规则去匹配

匹配成功输出结果

当然这只是一个简单的逻辑,如果需要实现更高高效快捷第一就是指纹库,第二就是代码运行的速率,提高线程

最终识别代码

首先就是指纹库的获取,这个的话我们就不直接获取了,使用的是%20EHole%20的指纹库

我们大概看看部分代码

{
"fingerprint":%20[{
 %20  "cms": "seeyon",
 %20  "method": "keyword",
 %20  "location": "body",
 %20  "keyword":%20["/seeyon/USER-DATA/IMAGES/LOGIN/login.gif"]
}, {
    "cms": "seeyon",
    "method": "keyword",
    "location": "body",
    "keyword": ["/seeyon/common/"]
}, {
    "cms": "Spring env",
    "method": "keyword",
    "location": "body",
    "keyword": ["servletContextInitParams"]
}, {
    "cms": "微三云管理系统",
    "method": "keyword",
    "location": "body",
    "keyword": ["WSY_logo","管理系统 MANAGEMENT SYSTEM"]
}, {
    "cms": "Spring env",
    "method": "keyword",
    "location": "body",
    "keyword": ["logback"]
}, {
    "cms": "Weblogic",
    "method": "keyword",
    "location": "body",
    "keyword": ["Error 404--Not Found"]
}, {
    "cms": "Weblogic",
    "method": "keyword",
    "location": "body",
    "keyword": ["Error 403--"]
}

{
    "cms": "Atlassian – JIRA",
    "method": "faviconhash",
    "location": "body",
    "keyword": ["981867722"]
}, {
    "cms": "OpenStack",
    "method": "faviconhash",
    "location": "body",
    "keyword": ["-923088984"]
}, {
    "cms": "Aplikasi",
    "method": "faviconhash",
    "location": "body",
    "keyword": ["494866796"]
}, {
    "cms": "Ubiquiti Aircube",
    "method": "faviconhash",
    "location": "body",
    "keyword": ["1249285083"]
}

简单看了一下逻辑可以发现和我们的指定方法应该差不多,逻辑就是首先根据 method 去选择方法,一个是 keyword 方法,一个是 faviconhash 方法,是一个大的判断,然乎下面就是根据具体的比如 body,title 等去识别了

代码如下

import json
import requests
import hashlib
import base64
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from concurrent.futures import ThreadPoolExecutor, as_completed
import argparse

# 加载指纹
def load_fingerprints(file='finger.json'):
    with open(file, 'r', encoding='utf-8') as f:
        data = json.load(f)
        if"fingerprint" in data:
            return data["fingerprint"]
        raise ValueError("指纹文件格式不正确,应包含 'fingerprint' 字段。")

# 获取 HTTP 响应
def get_http_response(url):
    try:
        headers = {
            "User-Agent": "Mozilla/5.0"
        }
        return requests.get(url, headers=headers, timeout=8, verify=False)
    except:
        return None

# 计算 favicon hash
def get_favicon_hash(url):
    try:
        favicon_url = urljoin(url, '/favicon.ico')
        res = requests.get(favicon_url, timeout=5, verify=False)
        if res.status_code == 200:
            m = hashlib.md5()
            b64 = base64.b64encode(res.content)
            m.update(b64)
            returnint(m.hexdigest(), 16)
    except:
        return None

# 匹配单条指纹
def match_one(fpr, res, fav_hash):
    method = fpr["method"]
    loc = fpr.get("location", "body").lower()
    kws = fpr["keyword"]

    if method == 'keyword':
        text_body = res.text or""
        text_head = "\n".join(f"{k}: {v}"for k, v in res.headers.items())

        # 处理 title 和 header 等
        if loc == 'header':
            spaces = [text_head, text_body]
        elif loc == 'title':
            soup = BeautifulSoup(text_body, "html.parser")
            title = soup.title.stringif soup.title and soup.title.stringelse""
            spaces = [title, text_body]
        elif loc == 'body':
            spaces = [text_body]
        else:
            spaces = [text_body]

        for space in spaces:
            for kw in kws:
                if kw.lower() in space.lower():
                    return True

    if method == 'faviconhash'and fav_hash is not None:
        for kw in kws:
            try:
                if fav_hash == int(kw):
                    return True
            except:
                continue

    return False

# 识别单个 URL 指纹
def match_fingerprint(url, fps=None):
    fps = fps orload_fingerprints()
    res = get_http_response(url)
    fav_hash = get_favicon_hash(url)

    matched = []
    for fpr in fps:
        if'cms' not in fpr or'method' not in fpr or'keyword' not in fpr:
            continue
        ifmatch_one(fpr, res, fav_hash):
            matched.append(fpr['cms'])

    print(f"[✓] {url} 指纹识别结果:{list(set(matched))}")
    return {url: list(set(matched))}

# 多线程执行
def run_multithread(urls, threads):
    fps = load_fingerprints()
    results = []
    with ThreadPoolExecutor(max_workers=threads) as executor:
        future_to_url = {executor.submit(match_fingerprint, url, fps): url for url in urls}
        for future in as_completed(future_to_url):
            results.append(future.result())
    return results

# 主程序入口
def main():
    parser = argparse.ArgumentParser(description="指纹识别脚本 - 支持多线程")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("-u", "--url", help="单个目标 URL")
    group.add_argument("-f", "--file", help="包含多个 URL 的文件")
    parser.add_argument("-t", "--threads", type=int, default=10, help="线程数(默认10)")
    args = parser.parse_args()

    if args.url:
        match_fingerprint(args.url)

    elif args.file:
        with open(args.file, 'r', encoding='utf-8') as f:
            urls = [line.strip() for line in f if line.strip()]
        results = run_multithread(urls, args.threads)

if __name__ == '__main__':
    main()

加入了支持多线程和支持多目标的思路

结合漏洞扫描

我们光目标识别后,还需要实现精准化打击,正好 Nuclei 引擎支持根据 tag 去寻找我们的目标,完美了

实现思路就是首先寻找我们的 tag,然后在漏洞库里面查询,把有 tag 的和没有 tag 的分别分开放好,然后根据有 tag 的去精准化识别运行,完成最后的精准化 POC 攻击

初步的代码如下

import json
import os
import threading
import time
import base64
import hashlib
import requests
import argparse
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from concurrent.futures import ThreadPoolExecutor, as_completed
from queue import Queue

requests.packages.urllib3.disable_warnings()

# ---------- 指纹识别部分 ----------

def load_fingerprints(file='finger.json'):
    with open(file, 'r', encoding='utf-8') as f:
        data = json.load(f)
        return data["fingerprint"]

def get_http_response(url):
    try:
        headers = {"User-Agent": "Mozilla/5.0"}
        return requests.get(url, headers=headers, timeout=8, verify=False)
    except:
        return None

def get_favicon_hash(url):
    try:
        favicon_url = urljoin(url, '/favicon.ico')
        res = requests.get(favicon_url, timeout=5, verify=False)
        if res.status_code == 200:
            m = hashlib.md5()
            b64 = base64.b64encode(res.content)
            m.update(b64)
            returnint(m.hexdigest(), 16)
    except:
        return None

def match_one(fpr, res, fav_hash):
    method = fpr["method"]
    loc = fpr.get("location", "body").lower()
    kws = fpr["keyword"]

    if method == 'keyword':
        text_body = res.text or""
        text_head = "\n".join(f"{k}: {v}"for k, v in res.headers.items())
        if loc == 'header':
            spaces = [text_head]
        elif loc == 'title':
            soup = BeautifulSoup(text_body, "html.parser")
            title = soup.title.stringif soup.title and soup.title.stringelse""
            spaces = [title]
        else:
            spaces = [text_body]

        for space in spaces:
            for kw in kws:
                if kw.lower() in space.lower():
                    return True

    elif method == 'faviconhash'and fav_hash is not None:
        for kw in kws:
            try:
                if fav_hash == int(kw):
                    return True
            except:
                continue

    return False

def match_fingerprint(url, fps):
    res = get_http_response(url)
    fav_hash = get_favicon_hash(url)
    matched = []

    for fpr in fps:
        if'cms' not in fpr or'method' not in fpr or'keyword' not in fpr:
            continue
        ifmatch_one(fpr, res, fav_hash):
            matched.append(fpr['cms'])

    print(f"[✓] {url} 指纹识别结果:{list(set(matched))}")
    return {"url": url, "cms": list(set(matched))[0] if matched else""}

def run_fingerprint_scan(urls, threads, output='res.json'):
    fps = load_fingerprints()
    results = []

    with ThreadPoolExecutor(max_workers=threads) as executor:
        future_to_url = {executor.submit(match_fingerprint, url, fps): url for url in urls}
        for future in as_completed(future_to_url):
            results.append(future.result())

    with open(output, 'w', encoding='utf-8') as f:
        json.dump(results, f, ensure_ascii=False, indent=2)

# ---------- Nuclei 扫描部分 ----------

class AutoNuclei:
    def __init__(self, res_file='res.json', tag_file='C:\\Users\\86135\\nuclei-templates\\TEMPLATES-STATS.json', thread_count=5):
        self.res_file = res_file
        self.tag_file = tag_file
        self.havetag_file = 'havetag.txt'
        self.notag_file = 'notag.txt'
        self.result_dir = 'result'
        self.thread_count = thread_count

        self.cms_targets = {}         # {cms: [url1, url2]}
        self.nuclei_tags = set()
        self.tagged_targets = {}      # {tag: [url1, url2]}
        self.untagged_targets = []

        self.task_queue = Queue()
        self.load_res_json()
        self.load_tags()
        self.classify_targets()
        self.save_targets()
        self.start_scan_threads()

    def load_res_json(self):
        with open(self.res_file, 'r', encoding='utf-8') as f:
            data = json.load(f)
        for entry in data:
            cms = entry.get("cms", "").lower()
            url = entry.get("url")
            if cms and url:
                self.cms_targets.setdefault(cms, []).append(url)

    def load_tags(self):
        with open(self.tag_file, 'r', encoding='utf-8') as f:
            tags_data = json.load(f)
        for item in tags_data.get("tags", []):
            if item["name"]:
                self.nuclei_tags.add(item["name"].lower())

    def classify_targets(self):
        for cms, urls in self.cms_targets.items():
            if cms in self.nuclei_tags:
                self.tagged_targets.setdefault(cms, []).extend(urls)
            else:
                self.untagged_targets.extend(urls)

    def save_targets(self):
        with open(self.havetag_file, 'w', encoding='utf-8') as f:
            for tag, urls in self.tagged_targets.items():
                for url in urls:
                    f.write(f"{tag}||{url}\n")

        with open(self.notag_file, 'w', encoding='utf-8') as f:
            for url in self.untagged_targets:
                f.write(url + '\n')

        if not os.path.exists(self.result_dir):
            os.makedirs(self.result_dir)

    def scan_worker(self):
        while not self.task_queue.empty():
            try:
                tag, url = self.task_queue.get(timeout=1)
                target_file = f"temp_{int(time.time() * 1000)}.txt"
                with open(target_file, 'w', encoding='utf-8') as f:
                    f.write(url)

                output_file = os.path.join(self.result_dir, f"{tag}_{int(time.time())}.txt")
                cmd = f"F:\\gj\\Vulnerability_Scanning\\nuclei\\nuclei.exe -l {target_file} -tags {tag} -o {output_file} -stats"
                print(f"[+] 扫描任务启动: {url} -> {tag}")
                os.system(cmd)
                os.remove(target_file)
            except Exceptionas e:
                print(f"[!] 线程错误: {e}")

    def start_scan_threads(self):
        for tag, urls in self.tagged_targets.items():
            for url in urls:
                self.task_queue.put((tag, url))
        threads = []
        for _ in range(self.thread_count):
            t = threading.Thread(target=self.scan_worker)
            t.start()
            threads.append(t)
        for t in threads:
            t.join()
        print("[✓] 所有扫描任务完成!")

# ---------- 主程序入口 ----------

def main():
    parser = argparse.ArgumentParser(description="指纹识别 + Nuclei自动化工具")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("-u", "--url", help="目标 URL")
    group.add_argument("-f", "--file", help="URL列表文件")
    parser.add_argument("--fp-threads", type=int, default=10, help="指纹识别线程数")
    parser.add_argument("--scan-threads", type=int, default=5, help="Nuclei 扫描线程数")
    args = parser.parse_args()

    urls = []
    if args.url:
        urls = [args.url]
    elif args.file:
        with open(args.file, 'r', encoding='utf-8') as f:
            urls = [line.strip() for line in f if line.strip()]

    print("[*] 正在执行指纹识别...")
    run_fingerprint_scan(urls, threads=args.fp_threads, output='res.json')

    print("[*] 指纹识别完成,开始 Nuclei 扫描...")
    AutoNuclei(
        res_file='res.json',
        tag_file=os.path.join(os.environ['USERPROFILE'], 'nuclei-templates', 'TEMPLATES-STATS.json'),
        thread_count=args.scan_threads
    )

if __name__ == '__main__':
    main()

学习网安实战技术课程,戳“阅读原文”


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:蚁景网安 《指纹识别+精准化 POC 攻击》

指纹识别+精准化POC攻击 网络安全文章

指纹识别+精准化POC攻击

文章总结: 本文提出一种结合指纹识别与Nuclei实现精准化POC攻击的方案。文章详细解析了基于特定文件、页面关键字、请求头及URL路径的指纹识别技术,提供了基
评论:0   参与:  0