攻防演练目标资产名称纠正工具

admin 2026-01-22 00:24:17 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 针对攻防演练中目标名称不准确影响资产搜集的问题,本文介绍了一款基于Python的自动化纠正工具。该工具通过调用riskbird.com接口批量查询,支持将目标简称或旧名转换为标准全称,具备自动匹配或人工选择模式,有效提升了演练前期的信息搜集效率与准确性。 综合评分: 85 文章分类: 红队,安全工具,渗透测试,实战经验


cover_image

攻防演练目标资产名称纠正工具

扶桑与彼岸花 扶桑与彼岸花

道一安全

2026年1月21日 09:32 北京

免责声明

道一安全(本公众号)的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。本文所提供的工具仅用于学习,禁止用于其他!!!

来源

原文地址:https://xz.aliyun.com/news/19064

原文作者:  扶桑与彼岸花

正文

在参与攻防演练时候,经常会出现目标单位出错的情况,导致在搜集资产时候发现查无此家.(例如浙江某医院第六院,直接给出简称浙江中医六院,亦或是某单位该了公司名但是备案信息等等并未发生变化等等).手动纠错费时费力,在拼手速的攻防演练前期阶段非常之吃亏,为此想要写一个脚本来实现大规模的目标名称纠错.

我的大致思路是找一个类似于爱企查的网站,抓包后进行参数替换实现批量请求.发现,爱企查,天眼查等等网站参数校验极为严格,很难实现这个功能.最终在https://riskbird.com/这个网站上实现了此办法.

def req_riskbird(company_name, token):
    url = "https://riskbird.com/riskbird-api/newSearch"
    headers = {        "Host": "riskbird.com",        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",        "Accept": "application/json",        "App-Device": "WEB",        "Content-Type": "application/json",        "Origin": "https://riskbird.com",        "Referer": "https://riskbird.com/search/company",        "Accept-Language": "zh-CN,zh;q=0.9",        "Cookie": f"token={token}; app-device=WEB;"    }
    payload = {        "queryType": "1",        "searchKey": company_name,        "pageNo": 1,        "range": 10,        "selectConditionData": "{\"status\":\"\",\"sort_field\":\"\"}"    }
    try:        response = requests.post(url, headers=headers, json=payload)        response.raise_for_status()  # Raise an exception for HTTP errors
        data = response.json()
        if data.get("code") == 20000 and data.get("success"):            # Extract company names from the response            company_names = []            for company in data.get("data", {}).get("list", []):                if "entName" in company:                    company_names.append(company["entName"])            return company_names        else:            print(f"Error: {data.get('msg', 'Unknown error')}")            return []
    except requests.exceptions.RequestException as e:        print(f"Request failed: {e}")        return []    except json.JSONDecodeError:        print("Failed to parse response as JSON")        return []

指定关检测”美的”进行测试,功能正常

接下来我们要实现自动化纠错.我的思路是两种模式,num参数为1时代表默认选择名字匹配率最高的公司,2 代表手动选择公司

def compare_company(company_name, num, token):
    # 调用 req_riskbird 函数获取公司名称列表    company_names = req_riskbird(company_name, token)
    if not company_names:        # 如果没有返回任何公司名,则返回空列表        print("未找到相关公司:",company_name)        return []
    if num == 1:        # 如果选择 1,返回第一个结果        return [company_names[0]]    elif num == 2:        # 如果选择 2,返回所有结果并允许用户手动选择        print("以下是搜索到的所有公司名称:")        for i, name in enumerate(company_names, 1):            print(f"{i}. {name}")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 用户选择公司&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("搜索单位:",company_name)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; selected =&nbsp;int(input("请输入选择的公司编号:"))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;1&nbsp;<= selected <=&nbsp;len(company_names):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[company_names[selected -&nbsp;1]]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("无效的选择")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;ValueError:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("无效的输入")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]&nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("无效的 num 参数")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]

直接指定参数2进行输入,功能正常.目标自然是从文件中进行读取

def&nbsp;read_file():&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; 读取同目录下的tar.txt文件,将每行内容(公司名称)存入列表并返回
&nbsp; &nbsp; 参数:&nbsp; &nbsp; &nbsp; &nbsp; 无
&nbsp; &nbsp; 返回值:&nbsp; &nbsp; &nbsp; &nbsp; list: 包含所有公司名称的列表
&nbsp; &nbsp; 异常:&nbsp; &nbsp; &nbsp; &nbsp; 如果文件读取失败,将抛出相应的异常&nbsp; &nbsp; """&nbsp; &nbsp; company_list = []
&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;with&nbsp;open('tar.txt',&nbsp;'r', encoding='utf-8')&nbsp;as&nbsp;file:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;line&nbsp;in&nbsp;file:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 去除每行的空格和换行符&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; company_name = line.strip()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;company_name: &nbsp;# 确保不添加空行&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; company_list.append(company_name)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;company_list
&nbsp; &nbsp;&nbsp;except&nbsp;FileNotFoundError:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;raise&nbsp;FileNotFoundError("错误:tar.txt 文件不存在")&nbsp; &nbsp;&nbsp;except&nbsp;IOError:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;raise&nbsp;IOError("错误:无法读取 tar.txt 文件")&nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;raise&nbsp;Exception(f"读取文件时发生错误:&nbsp;{str(e)}")

最终效果

比如这次这家单位使用了简称,在工具的帮助下成功纠错使得能够正常搜集信息,实现突破

浙江省中山医院,全称叫浙江中医药大学附属第三医院(浙江省中山医院)

最终脚本

import&nbsp;requestsimport&nbsp;jsonimport&nbsp;argparse
def&nbsp;read_file():&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; 读取同目录下的tar.txt文件,将每行内容(公司名称)存入列表并返回
&nbsp; &nbsp; 参数:&nbsp; &nbsp; &nbsp; &nbsp; 无
&nbsp; &nbsp; 返回值:&nbsp; &nbsp; &nbsp; &nbsp; list: 包含所有公司名称的列表
&nbsp; &nbsp; 异常:&nbsp; &nbsp; &nbsp; &nbsp; 如果文件读取失败,将抛出相应的异常&nbsp; &nbsp; """&nbsp; &nbsp; company_list = []
&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;with&nbsp;open('tar.txt',&nbsp;'r', encoding='utf-8')&nbsp;as&nbsp;file:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;line&nbsp;in&nbsp;file:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 去除每行的空格和换行符&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; company_name = line.strip()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;company_name: &nbsp;# 确保不添加空行&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; company_list.append(company_name)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;company_list
&nbsp; &nbsp;&nbsp;except&nbsp;FileNotFoundError:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;raise&nbsp;FileNotFoundError("错误:tar.txt 文件不存在")&nbsp; &nbsp;&nbsp;except&nbsp;IOError:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;raise&nbsp;IOError("错误:无法读取 tar.txt 文件")&nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;raise&nbsp;Exception(f"读取文件时发生错误:&nbsp;{str(e)}")
def&nbsp;req_riskbird(company_name, token):
&nbsp; &nbsp; url =&nbsp;"https://riskbird.com/riskbird-api/newSearch"
&nbsp; &nbsp; headers = {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"Host":&nbsp;"riskbird.com",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"User-Agent":&nbsp;"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"Accept":&nbsp;"application/json",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"App-Device":&nbsp;"WEB",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"Content-Type":&nbsp;"application/json",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"Origin":&nbsp;"https://riskbird.com",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"Referer":&nbsp;"https://riskbird.com/search/company",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"Accept-Language":&nbsp;"zh-CN,zh;q=0.9",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"Cookie":&nbsp;f"token={token}; app-device=WEB;"&nbsp; &nbsp; }
&nbsp; &nbsp; payload = {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"queryType":&nbsp;"1",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"searchKey": company_name,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"pageNo":&nbsp;1,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"range":&nbsp;10,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"selectConditionData":&nbsp;"{\"status\":\"\",\"sort_field\":\"\"}"&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; response = requests.post(url, headers=headers, json=payload)&nbsp; &nbsp; &nbsp; &nbsp; response.raise_for_status() &nbsp;# Raise an exception for HTTP errors
&nbsp; &nbsp; &nbsp; &nbsp; data = response.json()
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;data.get("code") ==&nbsp;20000&nbsp;and&nbsp;data.get("success"):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Extract company names from the response&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; company_names = []&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;company&nbsp;in&nbsp;data.get("data", {}).get("list", []):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;"entName"&nbsp;in&nbsp;company:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; company_names.append(company["entName"])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;company_names&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"Error:&nbsp;{data.get('msg',&nbsp;'Unknown error')}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]
&nbsp; &nbsp;&nbsp;except&nbsp;requests.exceptions.RequestException&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"Request failed:&nbsp;{e}")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]&nbsp; &nbsp;&nbsp;except&nbsp;json.JSONDecodeError:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("Failed to parse response as JSON")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]
def&nbsp;compare_company(company_name, num, token):&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; 该函数通过调用 req_riskbird 函数,获取与公司名称相关的搜索结果,&nbsp; &nbsp; 根据 num 的值来返回用户选择的企业名称。
&nbsp; &nbsp; 参数:&nbsp; &nbsp; &nbsp; &nbsp; company_name (str): 需要查询的目标公司名称&nbsp; &nbsp; &nbsp; &nbsp; num (int): 选择显示结果的方式,1表示选择第一个结果,2表示输出所有结果并手动选择&nbsp; &nbsp; &nbsp; &nbsp; token (str): 用户登录后获取的授权令牌,用于API鉴权
&nbsp; &nbsp; 返回值:&nbsp; &nbsp; &nbsp; &nbsp; list: 包含用户选择的公司名称的列表,若查询失败或没有结果,则返回空列表。
&nbsp; &nbsp; 异常:&nbsp; &nbsp; &nbsp; &nbsp; 若调用 req_riskbird 发生异常,将返回空列表。&nbsp; &nbsp; """
&nbsp; &nbsp;&nbsp;# 调用 req_riskbird 函数获取公司名称列表&nbsp; &nbsp; company_names = req_riskbird(company_name, token)
&nbsp; &nbsp;&nbsp;if&nbsp;not&nbsp;company_names:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 如果没有返回任何公司名,则返回空列表&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("未找到相关公司:",company_name)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]
&nbsp; &nbsp;&nbsp;if&nbsp;num ==&nbsp;1:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 如果选择 1,返回第一个结果&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[company_names[0]]&nbsp; &nbsp;&nbsp;elif&nbsp;num ==&nbsp;2:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 如果选择 2,返回所有结果并允许用户手动选择&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("以下是搜索到的所有公司名称:")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;i, name&nbsp;in&nbsp;enumerate(company_names,&nbsp;1):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"{i}.&nbsp;{name}")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 用户选择公司&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("搜索单位:",company_name)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; selected =&nbsp;int(input("请输入选择的公司编号:"))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;1&nbsp;<= selected <=&nbsp;len(company_names):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[company_names[selected -&nbsp;1]]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("无效的选择")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;ValueError:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("无效的输入")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]&nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("无效的 num 参数")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]

# Example usageif&nbsp;__name__ ==&nbsp;"__main__":&nbsp; &nbsp; parser = argparse.ArgumentParser(description="主程序功能:根据输入查询公司信息。")&nbsp; &nbsp; parser.add_argument("-n",&nbsp;"--num",&nbsp;type=int, choices=[1,&nbsp;2], default=1,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;help="选择查询方式:1 - 默认选择匹配度最高的公司;2 - 手动选择公司")&nbsp; &nbsp; parser.add_argument("-f",&nbsp;"--file",&nbsp;type=str, default="tar.txt",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;help="存放公司名称的文件路径,默认为当前目录下的 'tar.txt'")&nbsp; &nbsp; parser.add_argument("-t",&nbsp;"--token",&nbsp;type=str, required=True,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;help="风鸟网站的认证令牌,用于 API 鉴权")
&nbsp; &nbsp; args = parser.parse_args()
&nbsp; &nbsp; company_list=read_file()
&nbsp; &nbsp; res = []&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;company_list:&nbsp; &nbsp; &nbsp; &nbsp; res.extend(compare_company(i,args.num, args.token))&nbsp; &nbsp;&nbsp;for&nbsp;j&nbsp;in&nbsp;res:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(j)&nbsp; &nbsp;&nbsp;print(f"\n输入{len(company_list)}家公司,输出{len(res)}家公司")

点分享

点收藏

点在看

点点赞


免责声明:

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

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

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

本文转载自:道一安全 扶桑与彼岸花 扶桑与彼岸花《攻防演练目标资产名称纠正工具》

评论:0   参与:  0