跳过正文
  1. 文章列表/

漏洞赏金计划实战:从信息收集到高价值漏洞挖掘的系统方法

Elone Yue
作者
Elone Yue

引言
#

漏洞赏金计划 (Bug Bounty) 是安全研究员和企业双赢的合作模式。但要在数万竞争者中脱颖而出,需要系统的方法论和高效的工作流。本文将分享我从 Bug Bounty 中获取数万美元的经验。

Recon 方法论
#

攻击面映射
#

┌──────────────────────────────────────────────┐
│          攻击面映射层次                         │
├──────────────────────────────────────────────┤
│                                              │
│  Layer 1: 主域名 (example.com)                │
│    └─ Layer 2: 子域名 (api.example.com)        │
│      └─ Layer 3: 端点 (/api/v1/users)          │
│        └─ Layer 4: 参数 (/api/v1/users?id=X)   │
│          └─ Layer 5: 漏洞 (IDOR at id=X)       │
│                                              │
└──────────────────────────────────────────────┘

自动化 Recon Pipeline
#

#!/bin/bash
# recon_pipeline.sh - 自动化攻击面发现

DOMAIN=$1

# Step 1: 子域名枚举
echo "[*] Enumerating subdomains for $DOMAIN..."
subfinder -d $DOMAIN -silent | tee subs.txt
amass enum -d $DOMAIN -silent | tee -a subs.txt
assetfinder --subs-only $DOMAIN | tee -a subs.txt

# 去重
sort -u subs.txt -o subs.txt

# Step 2: 存活检测
echo "[*] Checking live hosts..."
httpx -l subs.txt -silent -o live_hosts.txt

# Step 3: 技术栈识别
echo "[*] Identifying technologies..."
nuclei -l live_hosts.txt -t technologies/ -o tech_findings.yaml

# Step 4: 端口扫描
echo "[*] Scanning ports..."
nmap -sS -p- -T4 -iL live_hosts.txt -oA port_scan

# Step 5: Wayback Machine 获取历史 URL
echo "[*] Fetching Wayback URLs..."
waybackurls $DOMAIN | tee wayback_urls.txt

# Step 6: 提取端点参数
echo "[*] Extracting endpoints with parameters..."
cat wayback_urls.txt | grep "=" | tee endpoints_with_params.txt

echo "[+] Recon complete. Results saved."

Python Recon 脚本
#

#!/usr/bin/env python3
"""
自动化漏洞扫描辅助工具
集成多种数据源,发现潜在漏洞入口
"""
import requests
import json
from collections import defaultdict
from urllib.parse import urlparse, parse_qs


class BugBountyRecon:
    """漏洞赏金 Recon 助手"""
    
    def __init__(self, domain: str):
        self.domain = domain
        self.subdomains = set()
        self.endpoints = defaultdict(list)
        self.vuln_patterns = {
            'IDOR': [],
            'SSRF': [],
            'SQLI': [],
            'XSS': [],
        }
    
    def enumerate_subdomains(self) -> set:
        """子域名枚举"""
        sources = [
            f"https://crt.sh/?q=%25.{self.domain}&output=json",
            f"https:// dns.bufferover.run/dns?q={self.domain}",
        ]
        
        for url in sources:
            try:
                resp = requests.get(url, timeout=10)
                if 'crt.sh' in url:
                    for entry in resp.json():
                        name = entry.get('name_value', '')
                        self.subdomains.add(name.lower())
                elif 'bufferover' in url:
                    data = resp.json()
                    if 'meta' in data and 'SV' in data['meta']:
                        for record in data['meta']['SV']:
                            parts = record.split(',')
                            if len(parts) > 1:
                                self.subdomains.add(parts[1].lower())
            except Exception as e:
                print(f"[-] Source error: {e}")
        
        return self.subdomains
    
    def discover_endpoints(self, subdomains: set) -> dict:
        """端点发现"""
        for sub in subdomains:
            parsed = urlparse(f"https://{sub}")
            path = parsed.path
            
            # 按路径模式分类
            if '/api/' in path:
                self.endpoints['api'].append(sub + path)
            if '/admin' in path or '/manage' in path:
                self.endpoints['admin'].append(sub + path)
            if any(ext in path for ext in ['.php', '.asp', '.aspx', '.jsp']):
                self.endpoints['legacy'].append(sub + path)
        
        return dict(self.endpoints)
    
    def identify_vuln_entrypoints(self, endpoints: dict) -> dict:
        """识别潜在漏洞入口"""
        for category, urls in endpoints.items():
            for url in urls:
                parsed = urlparse(url)
                params = parse_qs(parsed.query)
                
                # IDOR 可疑参数
                if any(p in parsed.query.lower() for p in ['id=', 'user_id=', 'account=']):
                    self.vuln_patterns['IDOR'].append(url)
                
                # SSRF 可疑参数
                if any(p in parsed.query.lower() for p in ['url=', 'redirect=', 'callback=', 'next=']):
                    self.vuln_patterns['SSRF'].append(url)
                
                # SQL 注入可疑参数
                if category == 'legacy' and params:
                    self.vuln_patterns['SQLI'].append(url)
                
                # XSS 可疑参数
                if any(p in parsed.query.lower() for p in ['search=', 'q=', 'query=', 'input=']):
                    self.vuln_patterns['XSS'].append(url)
        
        return self.vuln_patterns
    
    def run(self) -> dict:
        """执行完整 Recon"""
        print(f"[*] Starting Recon for {self.domain}")
        
        subdomains = self.enumerate_subdomains()
        print(f"[+] Found {len(subdomains)} subdomains")
        
        endpoints = self.discover_endpoints(subdomains)
        print(f"[+] Discovered {sum(len(v) for v in endpoints.values())} endpoints")
        
        vulns = self.identify_vuln_entrypoints(endpoints)
        for vuln_type, entries in vulns.items():
            if entries:
                print(f"[!] {vuln_type}: {len(entries)} potential entrypoints")
        
        return {
            'subdomains': list(subdomains),
            'endpoints': endpoints,
            'vulnerability_entrypoints': vulns,
        }


if __name__ == '__main__':
    import sys
    
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <domain>")
        sys.exit(1)
    
    recon = BugBountyRecon(sys.argv[1])
    results = recon.run()
    
    with open('recon_results.json', 'w') as f:
        json.dump(results, f, indent=2)
    print("[+] Results saved to recon_results.json")

高价值漏洞模式
#

IDOR (不安全的直接对象引用)
#

请求示例:
GET /api/v1/users/12345/orders HTTP/1.1
Host: api.target.com
Authorization: Bearer <user_token>

攻击: 将 12345 改为其他用户 ID
GET /api/v1/users/67890/orders HTTP/1.1

验证: 是否返回了其他用户的数据

SSRF (服务器端请求伪造)
#

常见入口:
- /api/external?url=http://attacker.com
- /api/webhook/callback=http://...
- /api/proxy?target=...

Bypass 技巧:
- DNS Rebinding
- @符号绕过: http://internal.server@attacker.com
- 十六进制 IP: http://0xac100a01 (172.16.10.1)
- IPv6: http://[::1]

Race Condition
#

# 并发请求测试脚本
import threading
import requests

def exploit_race_condition(session, url, data, count=50):
    """利用竞争条件实现无限提款"""
    results = []
    
    def send_request():
        resp = session.post(url, json=data)
        results.append(resp.status_code)
    
    # 同时发送多个请求
    threads = [threading.Thread(target=send_request) for _ in range(count)]
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    
    return results

# 使用场景: 优惠券重复使用、金额负数、并发转账

Nuclei 模板示例
#

id: custom-idor-check
info:
  name: IDOR Vulnerability Check
  severity: high
  author: elone-yue

requests:
  - method: GET
    path:
      - "{{BaseURL}}/api/v1/users/{{user_id}}/profile"
    
    headers:
      Authorization: "Bearer {{token}}"
    
    matchers-condition: or
    matchers:
      - type: word
        words:
          - '"email":'
          - '"name":'
        condition: and
      
      - type: status
        status:
          - 200

漏洞报告模板
#

# 漏洞报告: [漏洞类型] - [影响描述]

## 概述
简要描述漏洞及其影响。

## 环境
- URL: https://api.target.com/v1/users
- 浏览器: Chrome 120
- 操作系统: macOS 14

## 复现步骤
1. 登录用户 A 账户
2. 拦截请求 `GET /api/v1/users/12345/profile`
3. 修改 user_id 为 `67890`(用户 B 的 ID)
4. 发送请求

## 预期行为
服务器应返回 403 Forbidden

## 实际行为
服务器返回用户 B 的完整个人信息,包括邮箱、电话、地址

## 影响
- 任意用户数据泄露
- 可能用于钓鱼攻击的社会工程信息收集
- 违反 GDPR/CCPA 等数据保护法规

## 修复建议
在服务端验证请求者身份与目标资源的归属关系

总结
#

  1. Recon 决定上限——攻击面越大,漏洞概率越高
  2. 自动化辅助而非替代——工具发现入口,人工分析逻辑
  3. 报告质量影响奖金——清晰的复现步骤 = 更高的优先级

参考资源

  1. HackerOne: https://hackerone.com
  2. Bugcrowd: https://www.bugcrowd.com
  3. Nuclei: https://github.com/projectdiscovery/nuclei
  4. PortSwigger Web Security Academy: https://portswigger.net/web-security