关于 recon-sector-expansion
面向授权安全测试的技能,用于跨多个行业扩展侦察并批量测试新公司域名。它涵盖已测目标核查、证书透明度与人工发现、存活检查以及测试和结果分析流程。
主要功能
- 01去重已测试域名
- 02通过 crt.sh 和搜索发现域名
- 03筛除基础设施及无关结果
- 04检查候选站点是否可访问
- 05批量测试存活域名
- 06分析常见 Web 安全问题
适用场景
- 01将授权测试扩展到已知行业之外
- 02发现本地服务行业的测试目标
- 03检查并测试一批新发现的域名
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill recon-sector-expansion安装后在 Claude Code 中输入/recon-sector-expansion确认已加载。
详细介绍
RECON-SECTOR-EXPANSION — 跨未覆盖行业批量发现
适用场景
在获得授权的项目中,用于扩大对新行业的覆盖范围——不是深入调查某个已知目标,而是在 5-10 个不同行业中发现并测试 20 个以上的新公司域名。目标列表必须来自授权范围。批量扩展适用于范围明确的项目,不适用于无差别抓取。
信号:
- “在非受监管行业中再发现 20 个域名”
- “我们需要扩大覆盖范围;还有哪些目标没测试?”
- “在常见行业之外寻找新目标”
行业扩展工作流
阶段 1 — 覆盖范围审计
发现新目标之前,先了解已测试的目标:
# 1. Check existing target list
ALL_TARGETS="${OUTPUT_DIR:-./output}/sector-expansion/all_targets.txt"
ALL_MASSIVE="${OUTPUT_DIR:-./output}/sector-expansion/all_massive.txt"
# Extract all domains from both files
grep -ohE '[a-zA-Z0-9][a-zA-Z0-9.-]*\.[a-z]{2,}' "$ALL_TARGETS" "$ALL_MASSIVE" | sort -u > /tmp/targets_deduped.txt
echo "Already tested: $(wc -l < /tmp/targets_deduped.txt) domains"
# 2. Check what findings files exist
ls "${OUTPUT_DIR:-./output}"/sector-expansion/*_findings.md 2>/dev/null | wc -l
# 3. Identify which sectors have been covered by inspecting findings files
# Check for sector-specific keywords
for sector in "dentist" "dental" "gym" "fitness" "baker" "auto_body" "carpet" "laundry" "daycare" "pest" "tree" "pet"; do
count=$(grep -l "$sector" "${OUTPUT_DIR:-./output}"/sector-expansion/*_findings*.md 2>/dev/null | wc -l)
echo "Sector '$sector': $count findings files"
done
阶段 2a — 来源 1:crt.sh 证书透明度(本地服务行业优先)
对于本地服务行业(屋顶施工、景观美化、管道维修、泳池服务、暖通空调),由于没有全国连锁企业,crt.sh 是首选发现来源。这些企业通常使用描述性域名,例如 [name][SECTOR_EXAMPLE] 或 [city][SECTOR_EXAMPLE]。
crt.sh 查询模式
使用简单的行业关键词并选择 HTML 输出模式(JSON API 在宽泛查询时会返回 502/503 错误):
QUERY="roofing"
curl -s --max-time 40 --connect-timeout 10 \
"https://crt.sh/?q=${QUERY}&excluded=expired&dedup=Y" \
-H 'User-Agent: Mozilla/5.0' 2>/dev/null | \
grep -oE '>[A-Za-z0-9][A-Za-z0-9.-]*\.com<' | \
sed 's/^>//;s/<$//' | \
sort -u >> /tmp/all_crt_domains.txt
参数说明:
&excluded=expired— 仅包含当前证书&dedup=Y— 对证书去重-oE正则表达式 — 兼容 BusyBox(没有可用的-P标志)- 不使用
&output=json— JSON API 在宽泛查询时不可靠
行业关键词目录
查询以下所有行业以收集候选目标:
SECTORS="roofing landscaping pestcontrol dentist dentist fitness \
cleaningservice movingcompany photography vetclinic realtor hvac \
treeservice lawncare plumbing poolcleaning windowcleaning petsalon \
barbershop daycare carpetcleaning handyman lawfirm concrete \
autorepair petgrooming autobody remodeling"
for sector in $SECTORS; do
curl -s --max-time 40 --connect-timeout 10 "https://crt.sh/?q=${sector}&excluded=expired&dedup=Y" \
-H 'User-Agent: Mozilla/5.0' 2>/dev/null | \
grep -oE '>[A-Za-z0-9][A-Za-z0-9.-]*\.com<' | \
sed 's/^>//;s/<$//' >> /tmp/all_crt_domains.txt
sleep 2 # avoid rate limiting
done
过滤 crt.sh 结果中的噪声
crt.sh 会返回许多子域名和基础设施主机。请剔除以下模式:
import re
# Common noise patterns from crt.sh
skip_patterns = [
'^autodiscover\\.', '^vpn\\.', '^api\\.', '^mail\\.', '^remote\\.',
'^webmail\\.', '^crm\\.', '^ftp\\.', '^test\\.', '^dev\\.',
'^exchange', '^hostmaster', '^owa\\.', '^smtp\\.',
# Generic placeholder domains
'roofingcompany\\.com$', 'landscapingcompany\\.com$', 'vetclinic\\.com$',
]
然后根据域名名称匹配行业,为域名关联行业:
SECTOR_KEYWORDS = {
'roofing': ['roofing', 'roof', 'roofer'],
'landscaping': ['landscaping', 'landscape', 'lawn'],
'hvac': ['hvac', 'heating', 'cooling', 'air'],
'dental': ['dentist', 'dental'],
'pest-control': ['pest', 'mosquito'],
'daycare': ['daycare'],
'legal': ['lawfirm', 'lawfirm'],
'fitness': ['gym', 'fitness'],
'auto-repair': ['autorepair', 'auto', 'collision'],
'cleaning': ['cleaning', 'maid'],
'veterinary': ['vet', 'pet'],
'pool-services': ['pool', 'spa'],
}
噪声子域名过滤
对 crt.sh HTML 输出使用 grep 时,会获得大型托管服务商的条目。请排除:
autodiscover.*、vpn.*、api.*、mail.*、remote.*— 基础设施.*\.hvacrightnow\.com、.*\.hvacbrain\.com— SaaS 平台(非实际目标).*\.theroofingprofessor\.com、.*\.bakerroofing\.com— 大型组织的子域名.*\.singaporepools\.com、.*\.devsingaporepools\.com— 非美国目标
在去重前通过带排除模式的 grep -v 管道过滤,可节省时间。
阶段 2b — 来源 2:Google / 手动搜索(全国连锁企业优先)
对于由全国性/区域性连锁企业主导的行业(牙科、健身房、面包店、汽车钣喷),请使用 Google 搜索,因为连锁企业的域名很少包含行业关键词:
| 行业 | 候选目标查找方法 | 连锁企业示例 |
|---|---|---|
| 牙科连锁 | Google 搜索“top dental chains USA” | Aspen Dental、Gentle Dental、Coast Dental、DentalWorks、Heartland Dental、Pacific Dental |
| 健身房/健身 | Google 搜索“largest fitness chains USA” | F45、Barry's、CrossFit、Gold's Gym、24 Hour Fitness、LA Fitness、OrangeTheory |
| 面包店连锁 | Google 搜索“largest bakery chains USA” | Cinnabon、Crumbl、Insomnia Cookies、Sprinkles、Nothing Bundt Cakes |
| 汽车钣喷/碰撞维修 | Google 搜索“auto body repair chains USA” | ABRA、Caliber、Gerber、Service King、Fix Auto、Sterling、Crash Champions |
| 地毯清洁 | Google 搜索“carpet cleaning companies USA” | Chem-Dry、ServPro、Stanley Steemer、Rainbow International、Heaven's Best |
| 洗衣服务 | Google 搜索“laundry delivery service USA” | Poplin、Rinse、Washlava、LaundryHeap |
| 日托/托儿 | Google 搜索“largest daycare chains USA” | Bright Horizons、KinderCare、Goddard、Primrose、Children of America |
| 宠物美容 | Google 搜索“pet grooming chains USA” | Petco、PetSmart、Camp Bow Wow、Dogtopia |
| 害虫防治 | Google 搜索“pest control companies USA” | Terminix、Orkin、Ehrlich、Bulwark、Arrow |
| 树木服务 | Google 搜索“tree service companies USA” | Davey、SavATree、Arbor Care、Bartlett |
阶段 3 — 批量存活检测(Curl 探测)
收集到 50-60 个候选域名后,先过滤掉已测试的域名,再快速检查 HTTP:
# Filter against known targets
grep -v -f /tmp/targets_deduped.txt /tmp/candidates.txt | sort -u > /tmp/fresh_candidates.txt
# Quick alive check with curl (serial, ~2.5 min for 60 targets)
echo "=== Checking all candidates with curl ==="
for domain in $(cat /tmp/fresh_candidates.txt); do
code=$(curl -sk -o /dev/null -w '%{http_code}' --connect-timeout 5 --max-time 8 "https://${domain}" 2>/dev/null)
echo "$domain => $code"
done > /tmp/curl_alive.txt
# Extract alive domains (anything not 000/timeout)
grep -v "=> 000" /tmp/curl_alive.txt | grep -v "^$" | cut -d' ' -f1 > /tmp/alive_domains.txt
echo "Alive: $(wc -l < /tmp/alive_domains.txt) / $(wc -l < /tmp/fresh_candidates.txt) candidates"
阶段 4 — 完整测试流水线
然后对存活的域名运行完整的 6 步流水线。对于大规模目标(20 个以上),最高效的方法是使用 Python 批处理脚本:
#!/usr/bin/env python3
"""Batch test targets: httpx → WP REST → CORS → XMLRPC → ports"""
import subprocess, json, sys, os, re, time
OUTPUT_DIR = os.environ.get("OUTPUT_DIR", "./output") + "/sector-expansion"
def run(cmd, timeout=15):
try:
r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout)
return r.stdout + r.stderr
except subprocess.TimeoutExpired:
return f"TIMEOUT ({timeout}s)"
except Exception as ex:
return f"ERROR: {ex}"
def test_domain(domain, sector):
findings = {"domain": domain, "sector": sector, "wp": False, "wp_users": 0,
"cors_reflected": False, "xmlrpc_open": False}
# STEP 1: httpx probe
r = run(f"httpx -sc -title -tech-detect -server -no-color -u https://{domain} -timeout 10")
findings["http"] = r.strip()
# STEP 2: WordPress REST API check (3 paths)
for path in ["/wp-json/wp/v2/users", "/wp-json/", "/?rest_route=/wp/v2/users"]:
r = run(f'curl -sk -o /dev/null -w "%{{http_code}}" --max-time 10 --connect-timeout 10 "https://{domain}{path}"')
if r in ["200"]:
findings["wp_rest_status"] = f"{path} => HTTP {r}"
findings["wp"] = True
# Enumerate users
user_resp = run(f'curl -sk --max-time 10 --connect-timeout 10 "https://{domain}{path}"', timeout=12)
try:
users = json.loads(user_resp)
if isinstance(users, list):
findings["wp_users"] = len(users)
findings["wp_users_list"] = [u.get("name","") for u in users]
except:
pass
break
# Fallback: check page source for WP markers
if not findings["wp"]:
r = run(f'curl -sk --max-time 10 --connect-timeout 10 "https://{domain}"', timeout=12)
if "/wp-content/" in r or "/wp-includes/" in r:
findings["wp"] = True
# STEP 3: CORS test
target_url = f"https://{domain}/wp-json/wp/v2/users" if findings["wp"] else f"https://{domain}/"
r = run(f'curl -sk -H "Origin: https://evil.com" -D- --max-time 10 --connect-timeout 10 "{target_url}" | grep -i access-control', timeout=12)
if "Access-Control-Allow-Origin" in r:
findings["cors_reflected"] = True
findings["cors_credentialed"] = "Access-Control-Allow-Credentials" in r
# STEP 4: XMLRPC check
r = run(f'curl -sk -o /dev/null -w "%{{http_code}}" --max-time 10 --connect-timeout 10 -X POST "https://{domain}/xmlrpc.php"', timeout=12)
findings["xmlrpc_open"] = (r.strip() == "200")
# STEP 5: Port scan (top 20)
r = run(f'nmap --top-ports 20 -T4 --open -n {domain}', timeout=120)
ports = [line.split('/')[0] for line in r.split('\n') if re.search(r'^\d+/tcp\s+open', line)]
findings["ports"] = ports
# Severity calculation
score = sum([findings["wp"], bool(findings["wp_users"] > 0), findings["cors_reflected"], findings["xmlrpc_open"]])
findings["vuln"] = "HIGH" if score >= 3 else ("MEDIUM" if score >= 2 else ("LOW" if score >= 1 else "NONE"))
return findings
# Usage
domains = {"[TARGET_1]": "dental", "[TARGET_2]": "gym_fitness", ...}
for domain, sector in domains.items():
f = test_domain(domain, sector)
# Write findings.md
content = f"""## {domain}
| Field | Value |
|-------|-------|
| HTTP | {f['http'][:200]} |
| WordPress | {'Yes' if f['wp'] else 'No'}, users: {f['wp_users']} |
| CORS | {'Reflected' + (' WITH CREDENTIALS' if f.get('cors_credentialed') else '') if f['cors_reflected'] else 'Not reflected'} |
| XMLRPC | {'Open' if f['xmlrpc_open'] else 'Closed'} |
| Ports | {', '.join(f['ports']) if f['ports'] else 'none found'} |
| Sector | {sector} |
| Vuln | {f['vuln']} |
"""
with open(f"{OUTPUT_DIR}/{domain}_findings.md", 'w') as out:
out.write(content)
阶段 5 — 结果分析
检查以下高信号特征:
| 特征 | 识别方法 | 严重程度 |
|---|---|---|
| 带凭据的 CORS | /wp-json/wp/v2/users 上存在 Access-Control-Allow-Origin: http://evil.com + Access-Control-Allow-Credentials: true | 高 |
| 暴露的 WordPress 用户 | /wp-json/wp/v2/users 上的 REST API 返回包含姓名、别名和头像的用户对象数组 | 中 |
| 通配符 CORS | Access-Control-Allow-Origin: *(不带凭据) | 中 |
| XMLRPC 开放 | /xmlrpc.php 返回 HTTP 200(WAF 可能会在方法列表级别阻止请求) | 低至中 |
| 非标准服务开放端口 | 21(FTP)、3306(MySQL)、3389(RDP)、5900(VNC)、6379(Redis) | 不定 |
| 暴露的 PHPInfo | /info.php、/test.php 等会暴露 400 多条配置项 | 低 |
特定行业的连锁企业域名列表
整理的美国全国性/区域性连锁企业域名列表(截至 2026-06 已验证存活):
牙科
aspendental.com gentledental.com dentalworks.com coastdental.com
brightnow.com sagedental.com western-dental.com castledental.com
heartlanddental.com pacificdental.com dentalcarealliance.com
健身房/健身
[FITNESS_CHAIN] barrys.com crossfit.com goldsgym.com
24hourfitness.com lafitness.com orangetheory.com planetfitness.com
anytimefitness.com snapfitness.com crunch.com
面包店
cinnabon.com crumbl.com insomniacookies.com sprinkles.com
bakery.example.com restaurant.example.com donut.example.com
汽车车身维修/碰撞修复
abracollision.com serviceking.com sterlingautobody.com crashchampions.com
fixauto.com true2form.com auto-body-shop.com
calibercollision.com carstar.com gerbercollision.com maaco.com
地毯清洁
chemdry.com servpro.com rainbowintl.com heavenlycarpet.com
stanleysteemer.com zerorez.com coit.com
洗衣
poplin.com rinse.com washlava.com laundryheap.com
speedqueen.com spincyclelaundry.com
日托
brighthorizons.com childrenofamerica.com kindercare.com goddardschool.com
primroseschools.com montessori.com lajollamontessori.com tutortime.com
害虫防治
terminix.com orkin.com echols.com bulwarkpest.com
arrowpest-control.example.com dodsonbros.com massey-services.com
树木服务
treecare.com arborcare.com davey.com savatree.com
bartlett.com allstatetree.com firstchoicetree.com
屋顶工程(本地/区域 — 通过 crt.sh 发现)
aastro[SECTOR_EXAMPLE] abcarnes[SECTOR_EXAMPLE] americaschoiceroofers.com arvada[SECTOR_EXAMPLE]
bacon[SECTOR_EXAMPLE] baker[SECTOR_EXAMPLE] bricor[SECTOR_EXAMPLE] capitol[SECTOR_EXAMPLE]
charlottepro[SECTOR_EXAMPLE] coloradopro[SECTOR_EXAMPLE] eh[SECTOR_EXAMPLE] errdaddy[SECTOR_EXAMPLE]
fifthwall[SECTOR_EXAMPLE] freeman[SECTOR_EXAMPLE] ghatley.com hambro[SECTOR_EXAMPLE]
hollis[SECTOR_EXAMPLE] integrityrc.com kbfamily[SECTOR_EXAMPLE] mcas[SECTOR_EXAMPLE]
na[SECTOR_EXAMPLE] pabco[SECTOR_EXAMPLE] roofon.com roofwithfoster.com
sandiegocounty[SECTOR_EXAMPLE] springfield[SECTOR_EXAMPLE] tomtheroofer.com
universityroof.com vanguardroofingltd.com wallace[SECTOR_EXAMPLE]
景观绿化(本地/区域 — 通过 crt.sh 发现)
delliquadrilandscape.com dundeedig.com guardyouryardpa.com
landscapingsi.com miles[SECTOR_EXAMPLE] moss[SECTOR_EXAMPLE]
mountainlandscapingkc.com sarasota[SECTOR_EXAMPLE] trinas[SECTOR_EXAMPLE]
moss[SECTOR_EXAMPLE] eo[SECTOR_EXAMPLE] brucewilson[SECTOR_EXAMPLE]
HVAC(本地/区域 — 通过 crt.sh 发现)
airzonahvac.com bigfishhvac.com dormarhvac.com specializedhvac.com
总承包商及其他(通过 crt.sh 发现)
allysonsflowers.com [INSURANCE_CO] canopyroofers.com
gelinc.com rvroofrepairflorida.com spartanroofingbc.com
注意事项
-
不要只依赖一个关键文件来确定“已测试”的域名。
all_targets.txt和all_massive.txt可能不同。合并两者并用sort -u去重。 -
CloudFlare 会阻止部分站点的 WP REST API。 如果
/wp-json/wp/v2/users返回 HTTP 403,请尝试/?rest_route=/wp/v2/users,或在页面源代码中检查/wp-content/标记。 -
XMLRPC 可能返回 200,但阻止 system.listMethods。 CloudFlare 和其他 WAF 会阻止方法列表 XML 请求体,但会让
system.multicall的端点保持开放。请分别测试。 -
部分返回 301/302 的站点仍可能启用 CORS。 重定向响应可以携带 CORS 标头(brighthorizons.com 的 301 响应中就有通配符 CORS)。如果落地页不同,请测试重定向目标 URL。
-
BusyBox grep 的限制。 精简环境可能提供 BusyBox,其中不包含
grep -P。请改用带扩展模式的grep -oE。BusyBox 的find也不支持-printf;请改用-exec echo {} \;或 shell 循环。 -
crt.sh 速率限制。 请求过于频繁时会返回 HTTP 502/503。查询间隔应为 3 秒;如果连续出错,请等待 15-30 秒。JSON API(
&output=json)在宽泛查询时尤其不可靠 — 请改用 HTML 输出模式(&excluded=expired&dedup=Y)。 -
端口扫描耗时。
nmap --top-ports 20 -T4每个目标约需 3-5 秒。请在后台并行扫描 5-7 个目标。 -
非 WordPress 站点上的 CORS。 CloudFront 或 S3 上的通用静态站点也可能反射 CORS。请务必同时测试
/和已知的 API 端点。 -
Python JSON 解析边缘情况。 WP REST API 用户端点在受保护的端点上可能返回对象而非列表(HTTP 401 与 200 响应码不同)。请务必检查
isinstance(users, list)。
验证
- 行业域名生成 — 确认行业关键词能够生成候选域名:
echo 'roofing landscaping pestcontrol' | tr ' ' '
' | wc -l
2. **crt.sh 可访问性** — 确认 crt.sh CDX 端点可访问:
```bash
curl -s --max-time 10 --connect-timeout 10 -o /dev/null -w '%{http_code}' 'https://crt.sh/?q=test&excluded=expired&dedup=Y'
所有测试均用于验证行业扩展准备情况。
相关技能
web2-recon— 针对单个目标的技术测试流水线(httpx、WP 枚举、CORS、XMLRPC、端口扫描、JS 分析)recon-sector— 统一的参数化行业侦察,包含sectors.yaml中的 25 个行业