对接 xray 和微信实现自动告警(webhook)

本文的代码写法随着 xray 和第三方服务的升级改进会逐渐失效,请仅参考思路。在 xray Github 仓库 webhook 目录中有最新的实现代码

如何第一时间知道扫出了漏洞(find vuln)

对于安全工程师来说,扫描器发现了漏洞能第一时间给出告警是非常重要的,因为安全工程师使用的是 xray 的基础爬虫模式,爬虫一直在爬也不会一直人工刷新和查看漏洞报告,也有可能是使用的被动代理模式,让测试人员挂扫描器代理然后访问各个业务页面,但是不知道什么时间测试人员才开始和完成测试,也有可能是日志扫描模式,导入日志使用脚本进行 url 扫描,不知道什么时间才能重放完成。

还有很多公司自建了漏洞管理系统、工单系统等等,如果扫描器发现了漏洞可以自动同步这些系统也将会大大解放安全人员。针对这些场景 xray 有一种漏洞输出模式叫 webhook-output,在发现漏洞的时候,将会向指定的 url post 漏洞数据,demo 的代码就是

import requests
requests.post(webhook, json=vuln_info)

如果我们写一个中间的转换和转发层,就可以很方便的实现下面的功能了

  • 发送邮件、短信告警
  • 发送微信、企业微信、钉钉、slack告警
  • 漏洞信息同步到自己的数据库中
  • 为该漏洞创建一个工单
  • 使用其他的工具去验证漏洞是否存在

使用 webhook 做自动推送

本文就借助 Server酱企业微信机器人,来演示如何实时通知 xray 发现了漏洞。

xray 的 webhook 是什么

对于 xray,webhook 应该是一个 url 地址,也就是我们需要自己搭建一个 web 服务器,接收到 xray 发送的漏洞信息,然后在将它转发,借助于 Python 的 flask 框架,我们很快写了一个 webhook url 的 demo 出来。

from flask import Flask, request
import requests

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def xray_webhook():
    print(request.json)
    return 'ok'

if __name__ == '__main__':
    app.run()

使用 xray webscan --url http://pentester-web.vulnet/sqli/example1.php?name=root --plugins sqldet --webhook-output http://127.0.0.1:5000/webhook 测试,然后发现成功打印出了漏洞信息。

 * Serving Flask app "app.py"
 * Environment: development
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
{'data': {'create_time': 1642737377634, 'detail': {'addr': 'http://demo.aisec.cn/demo/aisec/js_link.php?id=2&msg=abc', 'extra': {'param': {'key': 'msg', 'position': 'query', 'value': 'aeltmuuikqaqokdvpawp'}}, 'payload': "'><ScRiPt>alert(1)</sCrIpT>", 'snapshot': [['GET /demo/aisec/js_link.php?id=2&msg=%27%3E%3CScRiPt%3Efddsnqpcqy%3C%2FScRiPt%3E HTTP/1.1\r\nHost: demo.aisec.cn\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0\r\nAccept-Encoding: gzip\r\n\r\n', "HTTP/1.1 200 OK\r\nCache-Control: no-cache, must-revalidate\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nDate: Fri, 21 Jan 2022 03:56:17 GMT\r\nServer: WAF3.0\r\nX-Powered-By: PHP/5.4.16\r\n\r\nArray\n(\n    [id] => 2\n    [num] => 22\n)\n<br><br> has this record. \r\n\r\n<br><br><br>\r\n\r\n\r\n\r\n\r\n\r\n<a href='?'><ScRiPt>fddsnqpcqy</ScRiPt>'>link  msg:'><ScRiPt>fddsnqpcqy</ScRiPt></a> (This link has XSS,eg:?msg=' style=x:expression() onmouseover=alert(1) ')\r\n\r\n\r\n<br><br><br>\r\n<hr>\r\n\r\n\r\n<a href='index.php'>go back</a>\r\n\r\n<br><br><br>\r\n"]]}, 'plugin': 'xss/reflected/default', 'target': {'params': [{'path': ['msg'], 'position': 'query'}], 'url': 'http://demo.aisec.cn/demo/aisec/js_link.php'}}, 'type': 'web_vuln'}
127.0.0.1 - - [27/Aug/2019 00:17:36] "POST /webhook HTTP/1.1" 200 -

接下来就是解析 xray 的漏洞信息,然后生成对应的页面模板就好了。需要参考文档。因为推送不适合发送太大的数据量,所以就选择了基础的一些字段。

from flask import Flask, request
import requests

app = Flask(__name__)


@app.route('/webhook', methods=['POST'])
def xray_webhook():
    data = request.json
    data_type = data['type']
    vuln = data["data"]
    # 因为还会收到 https://chaitin.github.io/xray/#/webhook/statistic 的数据
    if data_type == "web_vuln":
        return "ok"
    content = """## xray 发现了新漏洞

url: {url}

插件: {plugin}

发现时间: {create_time}

请及时查看和处理
""".format(url=vuln["target"]["url"], plugin=vuln["plugin"],
           create_time=str(datetime.datetime.fromtimestamp(vuln["create_time"] / 1000)))
    print(content)
    return 'ok'

if __name__ == '__main__':
    app.run()