导语:最近,我在琢磨着扩展一下我的自动漏洞挖掘引擎。我的第一个想法就是将二阶漏洞加入到我的子域名接管扫描过程中。在本文中,我会讲解我是如何解决这个问题的,并且如何更加高效的完成这个自动化的扫描过程。
最近,我在琢磨着扩展一下我的自动漏洞挖掘引擎。我的第一个想法就是将二阶漏洞加入到我的子域名接管扫描过程中。在本文中,我会讲解我是如何解决这个问题的,并且如何更加高效的完成这个自动化的扫描过程。关于这个主题,其实有一篇文章已经讲的很不错了,文章链接在这里,但我觉得还有些东西需要补充一下。
当网站在错误的地方使用“可接受的域名”时,就容易出现子域名二次利用漏洞。假如网站引用了外部域的JavaScript文件,当这个域名存在子域名接管漏洞时会发生什么?当JavaScript文件不可用时(比如域已经过期),这时浏览器就会加载失败,而且不易察觉。如果不是因为该JavaScript文件对网站功能极其重要(比如实时聊天功能)的话,管理员可能都注意不到网站的行为有什么异常。我们可以注册这个域名,并且放上我们自己的JavaScript文件,写入一个xss payload。这是一个经典的子域名接管案例,我在之前的文章中已经分析过了,文章链接在这里。下图解释了这个xss流程:
为什么叫做二阶漏洞呢?首先我们得知道一阶子域名漏洞的定义,一阶漏洞就是只针对目标应用程序子域所存在的子域名接管漏洞。而二阶漏洞的定义其实就是扩展了域的范围,对除了目标应用程序子域外,能够产生重大影响的域。
对于子域二阶漏洞的利用,网上至少有一个开源的利用工具:second-order。这个工具的问题是它没有检查本文所描述的所有范围。正因如此,所以这对于我想扩展它的功能来说是一个很好的开头,不过,我多少有点不自信,因为这个工具是用go语言写的。
二阶漏洞并不局限于JavaScript文件。我们也可以把这种方法应用到CORS漏洞上。建议大家去hackerone看下这篇报告,文章讲的内容正是我提到的。基本的思想就是:我们需要从某些位置提取链接和域,这些位置发生了子域名接管的话会导致严重的问题。那么这些位置具体在哪儿呢?如下:
· script标签—影响:XSS
· a 标签—影响:社工
· link标签—影响:点击劫持
· CORS响应头—影响:数据泄露
实现
现在我们来看看如何使用Python来实现它。实现过程如下图:
第一部分是由爬虫组成。爬虫的技术细节我就不多讲了。至于使用什么方案就看你自己了。有如下几种方案你可以选择:
· 仅请求找到的每个子域
· 进行有限的爬行(比如高度为1的BFS树)
· 进行完全爬行
任何这些爬虫产生的HTML文件都会进入到提取主机中(不过第一选择绝对不是爬行)。
提取过程需要几步来完成。我使用一个函数来处理每一步。我们现在再来深入地看一下这个Python脚本:
from bs4 import BeautifulSoup def extract_javascript(domain, source_code): ''' Extract and normalize external javascript files from HTML ''' tree = BeautifulSoup(source_code, 'html.parser') scripts = [normalize_url(domain, s.get('src')) for s in tree.find_all('script') if s.get('src')] return list(set(scripts))
这段代码会从HTML文件中的script标签里提取所有链接。我使用了BeautifulSoup这个模块来解析HTML。仔细看看代码的话,你会发现有一个未知的函数normalize_url。我很快就会解释这个函数:
def extract_links(domain, source_code): ''' Extract and normalize links in HTML file ''' tree = BeautifulSoup(source_code, 'html.parser') hrefs = [normalize_url(domain, s.get('href')) for s in tree.find_all('a') if s.get('href')] return list(set(hrefs)) def extract_styles(domain, source_code): ''' Extract and normalize CSS in HTML file ''' tree = BeautifulSoup(source_code, 'html.parser') hrefs = [normalize_url(domain, s.get('href')) for s in tree.find_all('link') if s.get('href')] return list(set(hrefs))
不要感到奇怪,我们这里是在对类似于script的标签进行提取。
import requests def extract_cors(url): r = requests.get(url, timeout=5) if not r.headers.get('Access-Control-Allow-Origin'): return cors = r.headers['Access-Control-Allow-Origin'].split(',') if '*' in cors: # Use your imagination here return [] return cors
这个脚本有些不同的地方,不过也不难理解。不过,表达多个来源域有很多不同的方法。我觉得可以用“;”作为分隔符。你可以自己进行研究,让它变得更加可靠。提供多个来源域的方法也会有所不同。
def normalize_url(domain, src): ''' (Try to) Normalize URL to its absolute form ''' src = src.strip() src = src.rstrip('/') # Protocol relative URL if src.startswith('//'): return 'http:{}'.format(src) # Relative URL with / if src.startswith('/'): return 'http://{}{}'.format(domain, src) # Relative URL with ? if src.startswith('?'): return 'http://{}/{}'.format(domain, src) # Relative URL with ./ if src.startswith('./'): return 'http://{}{}'.format(domain, src[1:]) # Absolute URL if src.startswith('https://') or src.startswith('http://'): return src # Else let's hope it is relative URL return 'http://{}/{}'.format(domain, src)
该函数尝试将给定的URL规范化为绝对形式。你可能知道,HTML中的src或者是href标签的参数中也可能会包含相对地址。这个normalize_url函数会返回URL的绝对形式,这样我们就可以轻易的从中提取域和其他部分。
不过我们只需要从我们的绝对URL中提取域名。用Python来完成这个任务也比较简单,如下:
from urllib.parse import urlparse def extract_domain(url): '''Extracts domain name from given URL''' return urlparse(url).netloc
现在可以将提取到的域转发到子域接管验证引擎中。之前我在一篇文章中介绍过如何创建一个子域接管引擎。这个过程应该能够识别更高层次的子域名接管漏洞。完整的代码已经放在我的GitHub上了。
这些漏洞并不常见,很不好找。在我的挖洞生涯中我只遇到过一次。不过,由于这个漏洞挖掘过程可以很轻易地实现自动化,所以把这个加入到你的自动化工作中也就是小事一桩了。没准以后运气好的话能够捡到一个漏洞呢。
你们可以参考一下我写的其他关于子域名接管的文章: