XSStrike源码分析-上

XSStrike是一款优秀的开源xss漏洞扫描器。

前言

XSStrike是一款优秀的开源xss漏洞扫描器,项目地址:

1
https://github.com/s0md3v/XSStrike

主要分为如下功能模块:

  • 模糊测试(waf&filter)
  • DOM XSS检测
  • 参数发现
  • Photon爬虫(JS lib scan)
  • Blind XSS支持
  • Bruteforce模式
  • Scan模式

上述列举模块部分存在一定的包含关系,如scan扫描时会默认进行dom xss检测和payload生成,为了方便分析各个模块的功能,而不是简单的理顺程序的运行顺序,从而将一些比较重要的模块从检测逻辑中进行了拆分。

下面就这些模块分析一下实现方式,如有分析不对的地方,欢迎指正~

Bug

截止目前:2020.8.29

代码分支:0ecedc1bba149931e3b32e53422d5b7c089ba9dc

version:3.1.5 Latest on 20 Dec 2019

在使用XSStrike进行dom测试的时候,项目中有几个Pull request并没有合并到主分支(有的Pull request逻辑是错误的…),如果你在运行过程中发现并没有输出或者信息不全,可以尝试修改以下代码。

修改dom.py,由于allControlledVariables变量会在每次newLine循环中清空,这将导致追踪的变量失效,不能完整反映js处理流程。

image-20200829215716689

修改colors.py,当检测到当前系统为mac or windows时,会关闭colors,这将导输出颜色全部配置为空,而dom检测中,有一处逻辑是:

1
2
if line != newLine:
highlighted.append('%-3s %s' % (str(num), line.lstrip(' ')))

line的处理逻辑大致为:

1
line = re.sub(r'\b%s\b' % controlledVariable, yellow + controlledVariable + end, line)

由于colorsFalseendred等参数始终为空,导致line始终等于newLine

image-20200829220720431

image-20200829221656543

模糊测试(waf&filter)

waf和过滤器探测需要通过命令后--fuzzer来指定开启,根据文档描述:

The fuzzer is meant to test filters and Web Application Firewalls. It is painfully slow because it sends randomly* delay requests and the delay can be up to 30 seconds. To minimize the delay, set the delay to 1 second by using the -d option.

模糊测试期间会随机产生延迟,并且ip有可能发生被ban的风险,如果非必要检测的话,建议不使用此功能。

wafDetector函数作为waf探测的主要函数,会构造一个恶意的请求,存在waf的话是肯定被检测出来的。

image-20200829173753767

代码会加载一个waf指纹数据库,为下面这种格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"360 Web Application Firewall (360)" : {
"code" : "493",
"page" : "/wzws-waf-cgi/",
"headers" : "X-Powered-By-360wzb"
},
"aeSecure" : {
"code" : "",
"page" : "aesecure_denied.png",
"headers" : "aeSecure-code"
},
"Airlock (Phion/Ergon)" : {
"code" : "",
"page" : "",
"headers" : "AL[_-]?(SESS|LB)"
}
}

当判定返回的状态码大于400时,会在返回报文的页面,状态码和headers中匹配特征数据库,按照一定的权重相加,当scoure不为0时,表示应用程序存在waf。

image-20200829174156851

进行完waf探测之后,会对参数进行模糊测试,调用fuzzer方法,xsschecker为一个特征字符串,用于检测是否在返回页面之中:

image-20200829175813101

fuzzer函数实现方式如下,函数将参数读取并替换为config中预先配置的fuzzes字典,在每次发送是会产生一个随机延迟,防止访问次数过快导致ip被ban。

image-20200829180627102

当发送request请求失败时,函数会有一个except过程,用于测试是否为发送请求过快或者waf策略导致发送失败,会在最低50秒后重试,如果仍被except捕获的话,log会打印ip被block的提示。

image-20200829181150756

当然,当发送给成功后,会检测时候绕过了waf的过滤,检测逻辑比较简单,结果一般分为绕过、黑名单、失败。

image-20200829181804725

DOM XSS检测

这个检测程序是执行过程中默认存在的,如果不需要dom xss检测,可以使用--skip-dom命令绕过dom检测。

image-20200829182844668

接下来查看下dom的检测逻辑,与其说dom xss检测,不如说对js代码进行源码扫描,追踪有危险的变量和检测有危险的dom操作。

image-20200829223314977

首先定义了sourcessinks两个pattern,第一个是有关dom变量获取的,第二个是有关dom操作的。

定义了allControlledVariables全局变量,用于追踪被危险操作赋值的变量,controlledVariable则作为for循环内的临时变量,将初次赋值的变量存储到allControlledVariables之中,当识别到sourcessinks中的关键词时,会进行颜色标记,然后与原变量newLine进行比较:

1
2
if line != newLine:
highlighted.append('%-3s %s' % (str(num), line.lstrip(' ')))

当检测到被标记时,会通过终端进行输出。

参数发现

使用--params命令开启此功能,参数发现是由Arjun项目提供的支持,项目地址:

Find hidden parameters by parsing HTML & bruteforcing.

1
https://github.com/s0md3v/Arjun

之所以先分析这个模块,因为后面进行爬虫或scan扫描时会用到此模块,开启此功能可以在不传入参数的情况下由扫描器自动发现。

image-20200830173106995

参数的获取有两种方式,一种是配置列表,另一种为正则发现input标签,如下:

image-20200830173703675

image-20200830173723248

接下来会调用checky函数进行自动参数替换和报文发现:

image-20200830174806295

Photon爬虫(JS lib scan)

爬虫模块是由Photon项目提供支持的,使用--crawl命令来开启爬虫扫描,-l命令来指定爬行深度,项目地址:

1
https://github.com/s0md3v/Photon

可以使用-t命令防止过多线程触发安全机制或网站瘫痪。

It is possible to make concurrent requests to the target while crawling and -t option can be used to specify the number of concurrent requests to make. While threads can help to speed up crawling, they might also trigger security mechanisms. A high number of threads can also bring down small websites.

通过用户传入的targetlevel,程序会对网站进行相应深度的爬取,使用python的concurrent.futures模块进行多线程异步执行:

image-20200830141104144

为防止重复爬取,会先进行集合运算,storage为所有爬取的url,processed为已经爬取的url。

逻辑与传统的爬虫类似,使用正则读取html中的潜在url,但有一点是其他爬虫功能所没有的,在爬去时会进行js漏洞扫描,用于发现之前存在漏洞的js框架版本。

核心函数为main_scanner,会对urifilecontent进行检测。

image-20200830151703606

跟进看一下,发现都是调用了scan函数和check函数:

image-20200830152049756

scan函数主要为漏洞发现,通过加载的漏洞数据库去匹配爬取的内容,数据库内容大致为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
"handlebars.js" : {
"bowername": [ "handlebars", "handlebars.js" ],
"vulnerabilities" : [
{
"below" : "1.0.0.beta.3",
"severity": "medium",
"identifiers": {
"summary": "poorly sanitized input passed to eval()"
},
"info" : [ "https://github.com/wycats/handlebars.js/pull/68" ]
},
{
"below" : "4.0.0",
"severity": "medium",
"identifiers": {
"summary": "Quoteless attributes in templates can lead to XSS"
},
"info" : [ "https://github.com/wycats/handlebars.js/pull/1083" ]
}
],
"extractors" : {
"func" : [ "Handlebars.VERSION" ],
"uri" : [ "/([0-9][0-9.a-z_-]+)/handlebars(\\.min)?\\.js" ],
"filename" : [ "handlebars(?:js)?-([0-9][0-9.a-z_-]+)(.min)?\\.js" ],
"filecontent" : [
"Handlebars.VERSION = \"([0-9][0-9.a-z_-]+)\";", "Handlebars=\\{VERSION:(?:'|\")([0-9][0-9.a-z_-]+)(?:'|\")",
"this.Handlebars=\\{\\};[\n\r \t]+\\(function\\([a-z]\\)\\{[a-z].VERSION=(?:'|\")([0-9][0-9.a-z_-]+)(?:'|\")",
"/\\*![\n\r \t]+handlebars v([0-9][0-9.a-z_-]+)"
],
"hashes" : {}
}

uri检测和filecontent分别会调用不同的正则去做检测。

check函数主要用来漏洞分级,生成详细的漏洞报告,也是去数据库中匹配,就不多做介绍了。

Blind XSS支持

使用--blind开启Blind XSS支持。

Using this option while crawling will make XSStrike inject your blind XSS payload defined in core/config.py to be injected to every parameter of every HTML form.

Blind Xss与二次注入类似,当前操作并不会直接产生危害,或许在其他页面调用的时候会触发漏洞。

config.py中定义blind xss payload,代码会在提交表单的时候将value替换为个人payload。

image-20200830160104345

表单分析源自于Arjun项目,项目地址:

1
https://github.com/s0md3v/Arjun

Bruteforce模式

通过命令行参数-f--file指定加载的payload,运行时会自动执行Bruteforce模式,此模式不会进行任何额外的检测,只会根据加载文件执行。

You can load payloads from a file and check if they work. XSStrike will not perform any analysis in this mode.

处理逻辑比较简单,就是单纯的参数替换,当响应报文中检测到payload时,即表示成功。

image-20200830170934197

Scan模式

作为XSStrike扫描器的核心部分,里面涉及的东西有点多。。放到下篇文章去讲。

Author: Sys71m
Link: https://www.sys71m.top/2020/08/30/XSStrike源码分析-上/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.