HackerOne漏洞案例 | 子域名劫持漏洞的挖掘指南

  • 内容
  • 相关

2018-09-05_173332.png

在HackerOne实时更新的公开漏洞推送Hacktivity消息中,我们可以发现,其中的子域名劫持漏洞(Subdomain Takeover)占比不少。自从2014年Detectify实验室发布了一系列子域名劫持攻击姿势的文章之后,众测行业出现了大量此类问题相关的上报漏洞。

子域名劫持漏洞的基本前提可以大致的解释为,发生了错误配置情况,对应主机指向了一个当前未在用的特定服务,这样一来,攻击者就能通过在该特定的第三方服务中注册账户,声明对该子域的接管权限,由此,在该子域上部署网络服务,实现对该子域有目的的利用。作为一位白帽和安全分析师,我每天都会遇到这类漏洞问题。今天,我就来和大家聊聊子域名错误配置导致的子域名劫持漏洞相关的理解、挖掘、利用和上报,文章假设读者具备了一定的DNS知识和子域名设置基础。

子域名劫持漏洞介绍

如果你此前不了解子域名劫持漏洞,想从基本原理听起,我这里就设计了一个简单的实例场景。在该场景中,假设example.com是你在参与漏洞众测的目标网站,经过对example.com的所有子域名进行枚举之后,发现了其中一个子域名subdomain.example.com,该子域名错误配置指向了一个GitHub页面。由此,我们可以先来看看该子域名的DNS记录,在这里假设该子域名所属的GitHub页面存在多条指向GitHub特定IP地址的A记录:

 

$ host subdomain.example.com

subdomain.example.com has address 192.30.252.153

subdomain.example.com has address 192.30.252.154

$ whois 192.30.252.153 | grep "OrgName"

OrgName: GitHub, Inc.

网页访问subdomain.example.com后,我们可以发现以下404响应页面:

01.png看到这里,大多数白帽可能会觉得有戏了。这个404页面表示,在域名对应网站的顶级根目录下没被注册部署任何网页内容,因此,我们可以尝试去注册把该子域名接管为我们个人的GitHub库所有。但是,请注意,出现这种情况,并不代表所有对应的域名都存在劫持漏洞。因为有一些域名应用可能还需要检查具体的HTTP和HTTPS响应情况,以此来判断域名控制权限,而另外有些域名就不存在劫持漏洞。

02.png这里,假设就存在子域名劫持漏洞吧。当我们把该子域名添加进入个人 GitHub 项目之后,就能把它部署上我们自己的Web内容了,也就是说,我们就能把子域名接管为我们自己所有了。如下可以让subdomain.example.com指向任何你部署的网页内容:

03.png二阶子域名劫持漏洞

这里所说的二阶子域名劫持漏洞,有点像过期坏链劫持(Broken Link Hijacking),这种情况下的子域名,并不属于目标网站所有,但却是用来运行目标网站的网页内容的。也就是说,如目标网站网页内容中某个资源需要从外部导入的第三方资源,举例来说,像js文件一样,那么,攻击者就可以通过JavaScript的Blob对象类型进行导入,从而声明对目标网站相关子域名的控制权限。

这种在网页页面的主机劫持可以导致存储型跨站漏洞,攻击者可以针对目标网站页面,利用这种模式来加载任意的客户端代码。我在此提出这种威胁,就是希望我们不要把想像力只限制在子域名身上,还可以延伸到代码审查和目标网站的主机映射等方面。

像下图网站中,存在导入的第三方资源http://subdomain.example.com/script.js,那么,能否存在subdomain.example.com可被劫持,从而我可以变换script.js实现对example.com的间接劫持呢?

04.png当然,也要说明的是,如果你想对某个子网站域名进行劫持,那么可以花点时间,去看看该网站上各个页面中的第三方导入资源是否能被劫持利用。

子域名枚举和探测

现在,我们对如何在错误配置的子域名上部署我们自己的网页内容有了大致了解,接下来,我就来介绍发现漏洞子域名的各种技术、技巧和工具。

在深入之前,我们需要区分检索( Scraping )和暴力猜解(Brute Forcing)的不同,因为这两种方法都能帮助你发现子域名,但最终结果却有所不同。检索是一种被动的侦测方式,它利用DNS Dumpster和VirusTotal等外部服务和资源,来收集属于某个特定主机的子域名。这种方式能快速检索出外部服务资源中之前加载过的子域记录,算是一种不费太多精力的子域名发现方式。如以下DNS Dumpster网站中记录的reddit.com子域名情况:

05.png检索( Scraping )方式中不仅中以包含索引页面,还可以添加进目标网站的GIT库、内容安全策略头、源代码和漏洞跟踪消息等反馈源,只要你能想得到,检索列表是非常之多的。我就经常更新我自己的检索列表资源库,反正你应用的技术越多越奇特,那么最终你发现的结果也会与众不同。所以,从这一点来说,在做漏洞众测时,我们一定要具备创新精神。

Sublist3r算是检索( Scraping )方式的一个简单子域名发现工具了,它利用了轻量级的Python脚本,从各种搜索引擎、SSL证书和DNS记录网站中来收集目标子域名。具体的安装和应用如下图所示:

 

$ git clone https://github.com/aboul3la/Sublist3r.git

$ cd Sublist3r

$ sudo pip install -r requirements.txt

06.png暴力猜解子域名时,我们可以依托字典进行迭代请求尝试,然后根据其响应来判断子域名的有效性。但请注意,如果目标网站开户了泛域名(Wildcard)模式,进行子域暴力猜解时,可能会得到很多误报响应。

泛域名模式(Wildcard)也就是说,所有的子域名解析都可能会对应到同一IP地址下,如a.example.com和ctk.example.com都会解析到同一个IP地址。使用泛域名,可以让域名支持无限的子域名,也可以防止用户输入错误的子域名,而无法访问网站。所以,这个时候,可以解析一个目标网站不可能使用的子域名,依其响应来判断是否可以正常解析,如果能正常响应,则证明其开启了泛域名模式。如下:

$ host randomifje8z193hf8jafvh7g4q79gh274.example.com

针对子域名暴力猜解,我个人认为最好的方式就是,根据你平时积累的经验,或个人感兴趣的方式,创建你自己的猜解字典。例如,我经常对 Atlassian Jira 系统和 GIT用例的漏洞挖掘较多,所以我会在子域名猜解字典中添加进 “jira” 和 “git” 等相关关键字。

如果你打算创建个人的子域名猜解字典,我强烈建议你可以参考 Jason Haddix 的字典,他花了很多精力,将各种子域名发现工具的不同列表合并成了一个广泛的字典列表。

指纹识别(Fingerprinting)

为了增加你的子域名发现结果,不管是检索( Scraping )还是暴力猜解(Brute Forcing)方式中,都可以采用一种名为指纹识别(Fingerprinting)的技术,这种技术可以通过对目标网站的通用字典创建,然后以此来显示出那些,你用普通字典列表无法识别的属于目标网站的资产。

一些经典的子域名发现工具

在这里,我要介绍一些好用的子域名发现工具:

Altdns

这是Shubham Shah开发的一个子域名递归暴力猜解工具,你先要创建一个目标网站存在的子域名字典 subdomains.txt,这就是你的通用fingerprint字典,然后再创建一个递归置换字典 words.txt,然后用Altdns命令:

./altdns.py -i subdomains.txt -o data_output -w words.txt -r -s results_output.txt 

进行子域生成发现。我喜欢用 Altdns 来生成字典列表,然后再配合其它工具来运行发现。

Commonspeak

Commonspeak也是Shubham开发的另外一个工具,它通过Google的BigQuery查询记录来生成字典列表,其中包含了当前每天更新的各类子域名,非常及时快速。你可以通过查看这篇文章,来了解Commonspeak的字典收集和子域提取机制。

SubFinder

这是一个兼具检索( Scraping )和暴力猜解(Brute Forcing)的子域发现工具,就我个人来说,我用SubFinder比Sublist3r多,SubFinder能从包含API接口在内的各种服务中来发现子域名,最终结果也相对较好。

Massdns

Massdns是一个非常快速的子域枚举工具,其它工具可能用15分钟才能完成,但用Massdns仅需一分钟。但如果你想用Massdns,得先指定一个有效的DNS存根解析器( Resolver),如这个https://public-dns.info/nameservers.txt,通过其中的host进行域名解析发现。如果你长期不更新这个解析器列表,结果也可能会出现误报。

$ ./scripts/subbrute.py lists/names.txt example.com | ./bin/massdns -r lists/resolvers.txt -t A -o S -w results.txt

流程自动化

在挖掘子域名劫持漏洞的过程中,自动化非常关键。顶级的白帽黑客总会长期关注目标网站的任何变动,或是对目标网站的所属子域名进行持续的状态跟踪。本文中,我们不谈具体的跟踪关注手段,相反,我会介绍一些简单技巧,以便能节省些许挖掘分析时间,实现一定程度的自动化。

我喜欢用的第一项自动化任务是从一些主机列表中过滤出实时有效的子域名。因为在子域名检索方法中,最后的结果可能为有些子域名是过期的,有些则是不可访问的,因此,我们需要检测出哪些主机对应的子域名是实时有效的。请记住,正如之后会看到的示例显示,虽然一些主机不能有效解析,但也存在被劫持可能。这里的自动化,我们就用host命令来实现吧,如果某个子域名不存活为无效,那么就会响应返回一个错误消息。

 

while read subdomain; do

if host "$subdomain" > /dev/null; then

# If host is live, print it into

# a file called "live.txt".

echo "$subdomain" >> live.txt

fi

done < subdomain-list.txt

把所有检测和发现机制抽象化后,可以表示为以下流程:

07.png接下来需要对子域名有个大致的了解,这里有两种显示模式,一种为运行子域名截图脚本抓取所有子域名网站截图,另一种为存储各个子域名网站的显示内容。做子域名截图,可以考虑工具EyeWitness,它能对目标列表子域名生成一个包含截图、响应头和标头信息的HTML文件。

$ ./EyeWitness -f live.txt -d out --headless

可能有时候,你只需要存储子域名网站的简单GET请求响应页面内容时,EyeWitness就显得有点大材小用了。这个时候,我会用Tom Hudson开发的工具meg,它会向目标子域名发送简单的请求并把响应内容进行存储为明文,meg相比EyeWitness显得更轻量级一些。

$ meg -d 10 -c 200 / live.txt

xxxxx.png特殊情况 

也存在一种特殊情况需要说明,Frans Rosén大牛曾在他的演讲《DNS hijacking using cloud providers – No verification needed》中提到,如果你遇到一些dead DNS records(废弃的DNS记录),不要就表面性地认为其不存在子域名劫持漏洞。据Frans Rosén的观点,host命令可能会出错,但如果用dig命令的话,可能就会发现一些dead records。

漏洞利用

现在,假设你可以控制目标网站所属的某个子域名,那么,接下来该做什么呢?当你想用这个错误配置的子域名来实现某些可能的攻击场景时,最关键的是需要去了解这个子域名与目标网站的核心服务存在些什么交互。

Cookies

利用子域名劫持漏洞,针对可控制的子域名subdomain.example.com进行web服务部署,可以窃取用户隶属于 example.com 的Cookie,以此实现劫持受害者会话的目的。

08.png利用在线前端编辑网站output.jsbin.com,我们可以对cookie进行编辑设置。如果确定目标网站存在会话ID是确知不变的攻击风险(Session Fixation)https://en.wikipedia.org/wiki/Session_fixation,并且使用了HTTPOnly类的cookie,那么你就可以对cookie进行设置,当受害者启动浏览器后,由于cookie的按序排列,你这里的恶意cookie将会优先于对方的新生成的cookie,从而间接实现了对受害者身份的劫持。

CORS跨域资源共享

跨域资源共享,Cross-Origin Resource Sharing (CORS), 允许 Web 应用服务器进行跨域的网页访问控制。在Web应用创建的某个域中,按照一组规则来允许某些网站可以访问提取包括认证数据在内的数据信息。以某些子域名是可信域名的前提下,一些Web应用还允许子域名执行跨域的HTTP请求。当你挖掘子域名劫持漏洞时,可以留意一下COSR头信息,在Burp Suite Pro专业版中就有这个检测功能,另外可以看看Web应用是否将子域名列入了白名单,这些设置都可能实现对Web授权用户的数据窃取。

Oauth 授权白名单化

与跨域资源共享,Oauth 授权过程同样具备一个白名单机制,藉此,Web开发者可以指定指定哪个回调URIs是可以接受的。这里的风险在于,当存在劫持漏洞的子域名被列入这个白名单中时,攻击者可以在Oauth授权过程中把用户会话重定向到先前那个存在劫持漏洞的子域名中,以此窃取用户的 Oauth 授权信息。

内容安全策略(Content-Security Policies)

可以说,内容安全策略是Web应用信任的另一个主机列表,CSP的目的在于限制哪些主机可以在应用中执行客户端代码。如果希望尽量减少跨站脚本的影响,这种方式非常有用。如果你可以劫持控制的子域名包含在白名单中,你就可以绕过CSP限制,在Web应用中执行恶意的客户端代码。

 

$ curl -sI https://hackerone.com | grep -i "content-security-policy"

content-security-policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; child-src www.youtube-nocookie.co

m; connect-src 'self' www.google-analytics.com errors.hackerone.net; font-src 'self'; form-action 'self'; frame-ancestor

s 'none'; img-src 'self' data: cover-photos.hackerone-user-content.com hackathon-photos.hackerone-user-content.com profi

le-photos.hackerone-user-content.com hackerone-us-west-2-production-attachments.s3-us-west-2.amazonaws.com; media-src 's

elf' hackerone-us-west-2-production-attachments.s3-us-west-2.amazonaws.com; script-src 'self' www.google-analytics.com;

style-src 'self' 'unsafe-inline'; report-uri https://errors.hackerone.net/api/30/csp-report/?sentry_key=61c1e2f50d21487c

97a071737701f598

点击劫持(ClickJacking)

像《Cure53 Browser Security White Paper》中提到的那样,在X-Frame-Options标头中,IE、Edge和Safari都支持ALLOW-FROM uri机制,表示该页面可以在指定来源的 frame 中展示,也就是说,如果你可劫持控制的子域名在该机制的白名单中,那么就可以在目标网页应用中构建欺骗页面,执行点击劫持(ClickJacking)攻击。

密码管理器的密码信息泄露

这一点可以不必在一些漏洞上报中进行考虑,但也是我们值得关注的方面。某些密码管理器,如LastPass会在一些主网站所属的子域名网站中执行自动密码填充功能,这相当于让网站设置了一个包含明文密码的非httponly类cookie,可以方便子域名劫持之后的深入利用。

09.png拦截电子邮件

安全研究者Rojan Rijal曾发现了Uber基于SendGrid服务的某个可劫持子域名,之后,利用该子域名,他成功拦截了Uber内部的公司电邮通信,获取了Uber官方$10,000美金的奖励。(翻墙-点此查看文字分析,点此 观看PoC视频

上报子域名劫持漏洞的注意事项

在你尝试上报子域名劫持漏洞之前,应该注意以下事项:

请确保在你可劫持控制的子域名上部署了属于你自己的Web内容;

部署的Web内容尽量简单干净,最好是一句话之类的标志,连图片都不要放;

最佳方法就是在你部署的Web内容HTML文件注释中包含了某个隐秘消息即可,在与厂商联系协调时,这就足以证明漏洞问题;

如果厂商给你授权,为了说明整体的威胁影响,你可以进一步对这种子域名劫持漏洞做出测试;

大多数情况下,如果你的漏洞报告中包含了子域名劫持漏洞的利用步骤,厂商都会都会认可这种漏洞

子域名劫持漏洞属于高危漏洞,在编写漏洞报告时,请认真一点,如果漏洞属实又不属于重复报,那么恭喜你,最终你可以获得厂商的大奖。

最后,感谢我的一众白帽好友Frans Rosén 、Filedescriptor、Mongo 和 Tom Hudson,是他们的宝贵意见,为我这篇文章奠定了基础。

*参考来源:HackerOne,clouds编译,转自FreeBuf

本文标签:

版权声明:若无特殊注明,本文皆为《w0ai1uo》原创,转载请保留文章出处。

本文链接:HackerOne漏洞案例 | 子域名劫持漏洞的挖掘指南 - https://www.w0ai1uo.org/359.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注