可对前端打包器所构建的网站进行一键扫描的Packer Fuzzer

可对前端打包器所构建的网站进行一键扫描的Packer Fuzzer_第1张图片
前言:Packer Fuzzer是一款对Webpack等前端打包工具所构造的网站进行快速、高效安全检测的扫描工具。当我们在Goby中遇到前端打包器所生成的站点时,联动Packer Fuzzer可以自动解析全部JS文件并提取该站点所有API及API参数,从而进行高效漏洞模糊检测。

0x001 最终效果

1.1 插件入口

安装完Packer Fuzzer Goby插件之后,可以在Web检测(Webfinder)的显示框内右侧看到一排“Packer Fuzzer”按钮:

可对前端打包器所构建的网站进行一键扫描的Packer Fuzzer_第2张图片
若对应开发端口资产类型为网页,也可以在响应栏目内看见“Packer Fuzzer”按钮:

可对前端打包器所构建的网站进行一键扫描的Packer Fuzzer_第3张图片
点击“Packer Fuzzer”,则会通过自带指纹规则检测对应目标站点是否存在对应特征,若不存在则会有如下提示:

可对前端打包器所构建的网站进行一键扫描的Packer Fuzzer_第4张图片
点击“OK”开启扫描,当插件检测到对应特征时则会直接开始扫描。无需担心多次点击按钮造成重复扫描的问题,当扫描任务开始之后脚本会生成对应的“文件锁”防止再次执行扫描任务,重复点击时将会看到如下提示:

可对前端打包器所构建的网站进行一键扫描的Packer Fuzzer_第5张图片

1.2 生成报告

当扫描结束之后,再次点击对应“Packer Fuzzer”即可查看丰富的API模糊检测报告:

可对前端打包器所构建的网站进行一键扫描的Packer Fuzzer_第6张图片

0x002 编写流程

2.1 插件所需变量

首先,我们需要确定一些插件所需的用户设置内容,在package.json文件加入以下三个键值:

 "Packer Fuzzer路径": {
      "type": "string",
      "default": "",
      "description": "请输入Packer Fuzzer的路径",
      "fromDialog": true
    },
    "Python3命令名": {
      "type": "string",
      "default": "python3",
      "description": "请输入在当前环境下的Python3的命令,也可以是绝对路径"
    },
    "扫描模式": {
      "type": "string",
      "default": "simple",
      "description": "可以选择高级模式(adv)或者普通模式(simple), 并不推荐高级模式"
    }
  • 第一个键值Packer Fuzzer路径很好理解,为用户下载的Packer Fuzzer扫描器存放位置,便于插件能顺利联动;
  • 第二个键值Python3命令便是python3在用户系统中的名称,默认为python3。因为有些用户在系统中将python3设置为:py3、python、python3.5或者并未设置相对路径,若我们在开发时直接写死则很容易出现调用失败。并且在笔者测试时(Big Sur Bêta),虽然在终端内使用python3命令调用的为python3.7.7版本,但是在Goby的node.js环境中调用python3则实际使用的是python3.8.2版本,这样会则会因为python3.8.2版本未安装对应的python扩展库导致调用失败:

可对前端打包器所构建的网站进行一键扫描的Packer Fuzzer_第7张图片
此时我们可以使用which命令查看终端中python3.7.7版本的安装位置,并将得到的值填入此参数(绝对路径调用)中从使插件能正常调用。

可对前端打包器所构建的网站进行一键扫描的Packer Fuzzer_第8张图片

  • 第三个键值扫描模式决定了Packer Fuzzer的扫描模式,默认为普通模式(simple),同时扫描器也支持高级模式(adv),但不推荐用户使用高级模式,这将会消耗大量的时间用于提取每个API的具体参数信息(故此版本插件不论此值修改为如何均使用普通模式进行扫描,此设置保留在此单纯因为比较好看)。

2.2 插件入口点

Web检测:使用了与《Xray插件》作者go0p!相同的判断方式,只有符合条件才会显示“Packer Fuzzer”按钮。
首先,资产类型必须为“https”、“http”、“web”三者其一:

let identical = {"web": true,"http": true,"https": true};

接着便会在Packer_Check中判断,若不符合则会返回false结果从而实现不显示对应按钮:

goby.registerCommand('Packer_Check', function (content) {
  if (identical[content.protocol]) return true;
  return false;
});

2.3 设置扫描锁定

点击“Packer Fuzzer”之后,程序会判断扫描锁文件是否存在,若存在则给出提示不进行后续操作:

if (fs.existsSync(lockPath)) {
  goby.showInformationMessage("Packer Fuzzer正在扫描中,可以稍后再来看看!");
} else {
  ......
}

扫描锁文件位于PackerFuzzer项目tmp目录下,命名格式为:当前项目ID + 当前目标IP + 当前目标端口 + 当前资产类型 + lock扩展名:

let lockPath = config["Packer Fuzzer路径"]["default"] + dirB + taskID + '_' + hostIP + '_' + hostPort + '_' + webProtocol + ".lock";

首次开启扫描时,本插件会使用如下命令生成扫描锁文件随后调用扫描函数:

fs.writeFileSync(lockPath,'lock it','utf8');
runScanner(hostIP,hostPort,webProtocol,webURL,taskID);

当然考虑到系统差异,我们对路径中的斜杠做了如下处理:

if (os.type() == 'Windows_NT') {
  dirA = '\\reports\\';
  dirB = '\\tmp\\';
} else {
  dirA = '/reports/';
  dirB = '/tmp/';
}

2.4 检测目标特征

点击“Packer Fuzzer”按钮之后程序会判断扫描锁文件是否存在,若存在则给出提示不进行后续操作:

let fingerprint = ['\\u003cnoscript','webpackJsonp','\\u003cscript id=\\"__NEXT_DATA__','webpack-','\\u003cstyle id=\\"gatsby-inlined-css','\\u003cdiv id=\\"___gatsby','\\u003cmeta name=\\"generator\\" content=\\"phoenix','\\u003cmeta name=\\"generator\\" content=\\"Gatsby','\\u003cmeta name=\\"generator\\" content=\\"Docusaurus'];

写指纹并不难,但被识别数据从何而来呢?我们知道Goby在扫描完成之后会保留每一个目标的banner信息,但这个API并非是在官方插件文档内公开的,那么我们便需要自己找出来。首先我们需要在Goby开发版中在控制台对关键操作下断点,之后我们便可以寻找到我们所需要的API详细信息及如何调用:

可对前端打包器所构建的网站进行一键扫描的Packer Fuzzer_第9张图片
可以看到getIpInfo需要传入三个参数,第一个是callback函数、第二个是当前任务ID、第三个是当前目标站点IP,之后此函数会将banner信息json格式化之后传入callback函数中调用。在了解了这些之后,我们便可以开始调用此功能:

getIpInfo(dealWebInfo,goby.getTaskId(),hostIP);

dealWebInfo函数的检测功能如下:

function dealWebInfo(result){
  taskID = result.data["taskId"];
  if (result.data["honeypot"] == 0){
    if (identical[result.data["protocols"][content.hostinfo]["protocol"]]){
      var flag = 0;
      for(var i = 0; i < fingerprint.length; i++){
        webJson = result.data["protocols"][content.hostinfo]["json"];
        webProtocol = result.data["protocols"][content.hostinfo]["protocol"];
        if(webJson.indexOf(fingerprint[i]) != -1){
          flag = 1;
        }
......

函数首先会检测是否为蜜罐环境,接着便是循环检测指纹是否存在于banner信息中,若存在则将flag的值设置为1。(由于无法检测JS文件的特征,故此功能并不能实现百分百准确检测)。

2.5 开始联动扫描

首先会检测flag的值是否为1,若不为1则显示提示并检测用户选项:

if(flag == 1){
  console.log("存在滴");
  XXXXX调用执行
} else {
  console.log("木有检测到");
  var check = confirm("貌似不是打包器所生成的站点,是否继续扫描?");
  if (check == true) {
    XXXXX调用执行
  }
}

接着我们会去检测是否为web资产,若是web资产则直接使用web地址作为目标检测地址;若为IP地址则使用http协议类型 + IP + 端口的方式对检测目标进行拼接:

if (webProtocol == "web"){
  targetURL = webURL + "/"; //加一个杠好看些
} else {
  if (webProtocol == "http"){
    targetURL = "http://" + hostIP + ":" + hostPort + "/";
  } else {
    targetURL = "https://" + hostIP + ":" + hostPort + "/";
  }
}

随后调用node.js的命令执行功能:

var process = require('child_process');
var cmd = 'cd ' + config["Packer Fuzzer路径"]["default"] + ' && ' + config["Python3命令名"]["default"] + ' PackerFuzzer.py -u ' + targetURL + ' -l zh -r html -s ' + taskID + '_' + hostIP + '_' + hostPort + '_' + webProtocol;
process.exec(cmd);

其中命令行详解如下:

cd Packer Fuzzer路径(空格需自己转义) && python3 PackerFuzzer.py -u 目标地址 -l 指定使用中文 -r 只生成html类型报告  -s 开启静默模式+指定报告名称 -t 指定使用普通扫描模式

会先切换到Packer Fuzzer路径下,然后使用“&&”连调引用命令开始进行扫描,一气呵成无需考虑系统差异。在WinNT或者其他内核之下均可正常执行。

2.6 生成扫描报告

和扫描锁文件命名方式类似,其报告位于Packer Fuzzer路径reports目录下:

let reportPath = config["Packer Fuzzer路径"]["default"] + dirA + taskID + '_' + hostIP + '_' + hostPort + '_' + webProtocol + ".html";

和扫描锁文件命名方式类似,其报告位于Packer Fuzzer路径reports目录下:

if (fs.existsSync(reportPath)) {
  goby.showIframeDia(reportPath, "Packer Fuzzer 扫描报告", "1777", "1777");
}

注:由于Goby限制,无法将iframe页面放至最大。

0x003 插件小结

第一次开发node.js的插件,发现坑还是挺多的,除了上面遇到的python环境问题,我还遇到了因为非I/O阻塞及callback无法取出返回值导致函数无法及时获取return内容的问题。此外由于懒得重启Goby所以一直在控制台的Sources中修改脚本并测试,但还是会出现突然卡住的情况,换句话说基本上是在面向控制台开发。

插件目前还并不够完善,计划下一版的改进内容如下:1. 根据Goby当前语言生成对应语言的报告;2. 此版本未设置获取连调运行异常状态,脚本只通过判断是否存在报告来判断扫描是否结束。若在扫描过程中异常退出,则会永远停在提示页面无法重新检测等(当然可以手动删除扫描锁文件及查看Packer Fuzzer自带的日志文件);3. 加入更多的扫描参数。

最后笔者代表Packer Fuzzer团队感谢您使用本插件及Packer Fuzzer扫描器。

Merci le destin de nous rencontrer, le moment que je t’ai rencontré est le moment le plus chanceux de ma vie. Il me faut apprécier à vous, la cerise qui peut me connaître par âme.

插件开发文档及Goby开发版下载:
https://gobies.org/docs.html
Packer Fuzzer项目地址:
https://github.com/rtcatc/Packer-Fuzzer

文章来自Goby社区成员:PoC Sir,转载请注明出处。
下载Goby内测版,请关注微信公众号:GobySec
下载Goby正式版,请关注网址:https://gobies.org

你可能感兴趣的:(Goby,插件,工具,js)