一、背景
上周将W13Scan目录结构整理了一番,觉得要深入研究还得从代码层,于是尝试编写一下插件;框架本身已经集成了XSS扫描插件;
本篇文章的XSS插件的编写单纯是为了学习这个框架,所以只支持GET型,了解插件的编写方法和原理即可。
W13scan 是基于Python3的一款开源的Web漏洞发现工具,它支持主动扫描模式和被动扫描模式,能运行在Windows、Linux、Mac上。
二、框架结构
在编写插件之前,我们需要对框架本身的目录结构有一定了解,由于W13Scan本身的文档不是太详细,我自己整理了一下,目录结构图下所示
├── api 通过API调用启动扫描
├── certs HTTPS证书存放目录
├── datahtml输出模板存放目录
├── fingprints指纹数据
│ ├── framework 框架
│ ├── os操作系统
│ ├── programing│ └── webserver web服务
├── lib 框架核心目录
│ ├── api
│ ├── controller
│ ├── core
│ ├── helper
│ ├── parse
│ ├── proxy
│ └── reverse
├── output扫描结果输出目录
├── scanners扫描器插件
│ ├── PerFile 针对每个文件,包括参数啥的
│ ├── PerFolder 针对url的目录,会分隔目录分别访问
│ ├── PerServer 对每个domain的
├── thirdpart
│ ├── requests
└── w13scan.py启动入口
在上方目录结构中,我们看到插件都放在scanners
目录中,入口文件则为w13scan.py
文件,因此这两个位置就是我们需要重点所关注的;现在我们需要去分析框架的运行流程。
三、运行流程
使用pycharm
编辑器打开文件 w13scan.py
,可以看到入口文件中的如下代码
def main():# 检查版本信息version_check()# 获取绝对路径root = modulePath()# 解析命令行参数cmdline = cmd_line_parser()# 初始化执行init(root, cmdline)
在上方代码中可以看到运行了初始化init(root,cmdline)
方法,按住ctrl
然后用鼠标点击跳转到方法详情,编辑器自动打开了文件 lib/core/option.py
,可以看到初始化的具体流程
def init(root, cmdline):cinit(autoreset=True)setPaths(root)# 指纹信息banner()# 从config.py读取配置信息_init_conf()# 从cmdline读取配置_merge_options(cmdline)# 设置端口信息_set_conf()initKb()# 加载插件initPlugins()# 输出配置信息_init_stdout()patch_all()
在上方代码中可以看到,里面有一个initPlugins()
方法,同样按住ctrl
然后点击方法名字,编辑器会自动打开文件 lib/core/option.py
,可以看到插件初始化的整个过程
def initPlugins():# 加载检测插件for root, dirs, files in os.walk(path.scanners):# 获取插件下的文件列表files = filter(lambda x: not x.startswith("__") and x.endswith(".py"), files)# 对每一个文件进行处理for _ in files:# 获取文件名q = os.path.splitext(_)[0]# 判断插件白名单if conf.able and q not in conf.able and q != 'loader':continue# 判断插件黑名单if conf.disable and q in conf.disable:continue# 文件绝对路径filename = os.path.join(root, _)# 加载该文件mod = load_file_to_module(filename)
在上方代码中可以看到初始化插件,其实就是扫描了插件目录的文件列表,然后挨个加载文件。
四、分析调试
为了证实这个猜想,我在遍历的位置进行了代码调试,加了print()
方法,来验证我的猜想,代码如下所示
# 获取文件名q = os.path.splitext(_)[0]print(q)print("\n")# 判断插件白名单if conf.able and q not in conf.able and q != 'loader':continue
找了一个靶场系统,然后使用w13scan的扫描命令运行,执行命令如下所示
pythonw13scan.py-u "http://192.168.152.135:8888/home/index.php?m=tiezi&a=index&bk=6"
命令执行,在控制台看到如下信息
(w13scan) D:\mycode\tools\w13scan\W13SCAN>pythonw13scan.py-u "http://192.168.152.135:8888/home/index.php?m=tiezi&a=index&bk=6"
________________
< w13scan v2.1.0 >
----------------
\\,__, ||(oo)\||___(__)\|| )\_ ||_w |\ |||| * Cower....
loader
analyze_parameter
backup_file
....插件列表,省略....
net_xss
swf_files
[11:23:49] [INFO] Load scanner plugins:29
在上方的信息中,看到scanners
目录下的文件列表,所以验证了我的猜想;
接下来我就可以正式编写插件了,为了防止编写过程中对插件目录造成损坏,我将scanners
目录复制了一份,如下图所示
接着我回到scanners
目录,在目录里面有29个插件,调试的时候不是太方便,我先将其他插件都删除,为了参考插件怎么编写的,我留下一个,如下图所示
![](https://i-blog.csdnimg.cn/blog_migrate/efd589940fbdc65f981ad91595cea217.png)
在上图中,我只留下了一个backup_file.py
插件,用于编写自己的插件参考;同时我将这个插件改成自己插件的名字,如下图所示
![](https://i-blog.csdnimg.cn/blog_migrate/6dd6eeb060e2c837ce9cb12bd0868bc9.png)
在上图中,我将插件文件名子改为了xss_test.py
,再次运行,看看是否能正确运行,运行结果如下图所示
![](https://i-blog.csdnimg.cn/blog_migrate/6598633d38e4a404528040dc5f2f0267.png)
在上图中可以看到依然是可以运行的,同时插件名字也发生了变化,变成了xss_test
文件
五、编写插件
现在我们就开始编辑xss_test.py
插件,使用pycharm打开后,看到的代码如下图所示
![](https://i-blog.csdnimg.cn/blog_migrate/e7376cbfc937795f718dac1bc46422d1.png)
在上图中可以看到插件代码里面有两个方法audit
和_check
,我做了下分析,audit
才是对外的方法,_check
方法是插件内部的方法,我们不需要,直接删除即可;
接着我们新建一个audit
方法,同时备份之前的audit
方法为audit_bak
作为参考,如下图所示
![](https://i-blog.csdnimg.cn/blog_migrate/afb553e304f7fd10f751eaa95465f577.png)
在上图中,我新建了一个audit
方法,并接收了请求头信息和要请求的URL地址,并给出了要实现XSS漏洞检测的三个步骤:
1.准备poc
2.发送请求
3.判断返回数据里面是否包含了poc
接着我就开始实现这三个步骤,首先去准备poc代码,如下代码所示
# 接收头信息headers = self.requests.headers# 我们不要URL地址中的参数部分url = self.requests.netloc# 从这里单独接收参数,字典类型params = self.requests.params# 这里备份一下字典,不要使用同一个内存地址paramsBak = params.copy()# 1. 准备pocpayloads = ["1'\"()&%<acx><ScRiPt >prompt(915149)</ScRiPt>","<svg/onload=alert(1)>","\"><script>alert(document.cookie)</script>"]
接着我需要将poc代码和URL地址结合,生成一个带有攻击参数的链接地址,代码如下所示
# 每一个payloads都测试一遍for payload in payloads:# 每一个参数都需要测试for key, val in params.items():# 每次只测试一个参数,所以需要将之前的字典覆盖params = paramsBak.copy()# 将字典里的值改变,然后放到另外一个函数生成一个URL地址params[key] = payloadnUrl = self.createUrl(url, params)
生成如下URL地址:
http://192.168.152.135:8888/home/index.php?m=<svg/onload=alert(1)>&a=index&bk=6
或者如下:
http://192.168.152.135:8888/home/index.php?m=tiezi&a=<svg/onload=alert(1)>&bk=6
依次将poc代码替换到原有请求参数当中,接下来就是使用python去请求这个地址,并查看返回结果是否包含了poc代码,如果包含了poc代码说明后端没有做过滤处理,代码如下所示
# 2. 发送请求r = requests.get(nUrl, headers=headers, allow_redirects=False)# 如果返回值是200,说明页面可以访问if r.status_code == 200:# 3.判断返回数据里面是否包含了poc,包含了说明存在XSSif payload in r.text:# 将结果返回给框架,统一存储result = self.new_result()result.init_info(nUrl, "XSS检测", VulType.BRUTE_FORCE)# 存储扫描结果result.add_detail("payload请求", r.reqinfo, "请求返回结果", "插件备注信息", nUrl, "", PLACE.GET)self.success(result)
代码的含义在上面的备注信息中已经有说明,就不再过多赘述了,接下来我们再次运行W13Scan
,运行命令如下所示
pythonw13scan.py-u "http://192.168.152.135:8888/home/index.php?m=tiezi&a=index&bk=6"
命令运行之后,控制台输出的信息如下所示
在上图中可以看到我们的插件已经成功运行,并检测到了XSS漏洞
六、结果验证
接下来我复制其中一个带有poc的URL地址,放到浏览器去运行,如下图所示
![](https://i-blog.csdnimg.cn/blog_migrate/ef26988542a43482a050bf1fe6a245e1.png)
在上图中可以看到浏览器触发了XSS代码,弹出了cookie值,至此编写XSS检测插件就完成了,当然这个插件还不够完善,有兴趣的可以自己再深入研究~
完整的poc代码可以参考:
https://gitee.com/songboy/codes/kodyj714izqbpgv8cu2n390
作者:汤青松
日期:2020-12-08