看我如何分析并渗透WebSocket和Socket.io

标签: WEB安全 websocket 渗透 | 发表时间:2018-12-02 13:00 | 作者:Covfefe
出处:https://www.freebuf.com

Websocket简介

WebSocket是一种允许浏览器和服务器建立单个TCP连接然后进行全双工异步通信的技术。由于它允许实时更新,而浏览器也无需向后台发送数百个新的HTTP polling请求,所以对于web程序来说,WebSocket非常流行。这对于测试者来说是不好的,因为对WebSocket工具的支持不像HTTP那样普遍,有时候会更加复杂。

除了BurpSuite之外,还有一些其他工具可用于处理WebSocket。不过经过测试,它们都不怎么理想。

Zed Attack Proxy (ZAP)

Pappy Proxy

Man-in-the-Middle Proxy (mitmproxy)

WebSocket/Socket.io (WSSiP)

如果你对使用Websocket进行渗透测试感兴趣,那么可以查看这篇文章:

https://www.blackhillsinfosec.com/command-and-control-with-websockets-wsc2/

而在这篇文章中主要会讲socket.io,它是一个很流行的JavaScript WebSockets库。在GitHub上它有多流行呢?—已经有超过41.4的star了。

1.jpg

在NPM上,它在WebSocket中排行第二和第三。

2.jpg

另外,OWASP Juice-Shop这样非常棒的项目也使用了socket.io库,所以本篇文章中将使用websocket.io进行演示。

https://github.com/bkimminich/juice-shop/search?utf8=%E2%9C%93&q=socket.io&type=

在本文中,我们假设你已经熟悉使用BurpSuite测试Web应用程序,所涵盖的所有内容都可以在其社区版本中完成。不用多说,现在开始吧。

如果我们在浏览器中访问Juice-Shop,则可以在后台快速查看WebSocket流量。你也可以在BurpSuite中通过Proxy-> WebSockets历史记录找到。

由于协议的无状态特性,HTTP需要始终发送请求/响应对,而WebSocket是一种有状态协议。这意味着你可以从服务器获得任意数量的传出“请求”和任意数量的传入“响应”。由于底层连接是保持打开的TCP,因此客户端和服务器可以随时发送消息而无需等待对方。这就是为什么WebSocket历史记录与你习惯查看的HTTP历史记录存在差异。

3.jpg

在此界面中,你可以看到发送和接收的单字节消息。但是,当应用程序执行一些有趣的操作时,你就可以看到具有更大负载的消息。

4.jpg

BurpSuite具有测试WebSockets的能力,你可以实时进行拦截和修改,但WebSocket没有Repeater,Scanner或Intruder功能。默认情况下,如果要在BurpSuite中启用WebSocket拦截,你只需要打开主拦截就好了。

5.jpg

6.jpg

这样一来,你就可以通过与HTTP相同的方式获取所截获的WebSocket消息。同时也可以在拦截窗口中编辑它们。

7.jpg

在WebSockets历史记录选项卡中可以查看已编辑的消息。

8.jpg

将WebSocket降级为HTTP

方法一:使用Socket.io的HTTP回退机制

一个非常奇怪的点是,有时在HTTP历史记录中也能看到类似Websocket历史记录中的消息,回想一下,这些比较有趣的WebSocket消息需要解决记分板相关问题,下图显示了来自服务器的相同响应,但这次是在HTTP历史记录中。由此可以看出socket.io能够通过WebSocket或HTTP发送消息。

9.jpg

在所观察的请求中,传递的参数值有些为“websockets”,而有些则是“polling”。那么据推测,可能为了防止WebSockets在应用程序中不受支持或被阻止,才允许使用HTTP。

socket.io文档中解释了“polling”和“websockets”如何作为两个默认传输选项。它还介绍了如何通过将WebSockets指定为唯一传输方式来禁用polling。我认为反过来也是如此,我可以指定polling作为唯一的传输机制。

https://socket.io/docs/client-api/#with-WebSocket-transport-only

通过搜索socket.io.js源代码,我找到了以下内容:

  this.transports=n.transports||["polling","WebSocket"]

10.jpg

这行代码会将一个名为transports的内部变量设置为传入的值,如果传入的值为false/empty,则为默认的[“polling”,“websocket”]。这很符合我们对polling和WebSocket的默认传输的推测。现在通过Burp中的Proxy->Options下设置匹配并替换规则来更改这些默认值,看看会发生什么。

11.jpg

成功了!添加规则后,刷新页面(需要启用Burp的内置规则“Require non-cached response”或执行强制刷新),数据不再通过WebSockets进行通信。进展不小,但是如果使用的应用程序已经提供了优先于我们的新默认值的传输选项呢?在这种情况下,我们可以修改匹配和替换规则。以下规则应适用于socket.io库的不同版本,并忽略应用程序开发人员所指定的任何传输方式。

12.jpg

以下是要使用的字符串,务必将其设置为正则表达式匹配:

     

this\.transports=.*?\.transports\|\|\["polling","websocket"]

this.transports=["polling"]

方法二:中止Websocket升级

方法一只能用于于socket.io,可能会扩展到其他客户端库。但是,以下方法应该更加通用,因为它以WebSockets协议本身为目标。

经过分析,我发现WebSockets首先通过HTTP进行通信,以便与服务器协商并“升级”为WebSocket。其中重要的部分是:

1)客户端通过一些WebSocket特定header发送升级请求。

13.jpg

2)服务器响应状态码为101 Switching Protocols,以及WebSocket header。

14.jpg

3)通信转换到WebSocket,此特定会话不再使用HTTP。

WebSockets RFC文档第4.1节提供了有关如何中断此工作流的各种信息,以下是 https://tools.ietf.org/html/rfc6455#section-4.1的摘录,并附加了观点。

1.如果从服务器收到的状态码不是101,则客户端响应HTTP [RFC2616]。特别情况下,收到401状态码时,客户端可能会执行身份验证;服务器也可能会通过3xx状态码重定向客户端(但客户不需要遵循)等。否则按以下步骤进行。

2.如果响应缺少Upgrade header,或Upgrade header包含的值与“WebSocket”的ASCII不匹配,则客户端必须关闭WebSocket连接。

3.如果响应缺少Connection header,或Connection header包含的值与“WebSocket”的ASCII不匹配,则客户端必须关闭WebSocket连接。

4.如果响应缺少Sec-WebSocket-Accept header,或Sec-WebSocket-Accept header的值并非是由Sec-WebSocket-Key(作为字符串,未经base64解码)与字符串”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″串联起来的字符串(忽略任何前导和尾随空格)的base64编码后的SHA-1值的话,则客户端必须关闭WebSocket连接。

5.如果响应中包括Sec-WebSocket-Extensions header,并且header要求使用的扩展并没有出现在客户端的握手消息中(服务器指示的扩展并非是客户端所请求的),则客户端必须关闭WebSocket连接。(解析header以确定请求哪些扩展的问题,将在 第9.1节中讨论)

考虑到这些“连接必定被关闭”的条件,我想出了以下一套替换规则,这些规则应该包含了所有五个的失败条件。

15.jpg

一旦使用这些规则,所有WebSocket升级请求都会失败。由于socket.io默认情况下无法使用HTTP,因此已经达到所需的效果。其他库的表现可能不同,并导致你正在测试的应用程序出错。但我们的工作就是让软件做一些不应该做的事情!

16.jpg

原始响应看起来像这样,并且会使客户端和服务器转换到WebSocket进行通信。

17.jpg

相反,客户端从服务器收到此修改后的响应,会关闭WebSocket连接。

18.jpg

我在测试中遇到的一件事是,在将这些匹配和替换规则加入后,客户端在重试WebSocket连接时非常持久,并在我的HTTP历史记录中引起了大量不必要的流量。如果你正在处理socket.io库,则最简单的方法是使用上面的方法1。如果你有不同的库或其他情况,则可能需要添加更多规则来使客户端服务器不支持WebSocket。

将Burp Repeater作为Socket.io客户端

由于我们强制通过HTTP而非WebSockets进行通信,所以现在可以添加自定义匹配并替换将应用于已经通过WebSockets流量的规则!接下来,可以使用Repeater,Intruder和Scanner等工具,这些更改将特定于socket.io库。不过现在还有两个问题:

1.每个请求都有一个会话号,任何无效请求都将导致服务器终止该会话

2.每个请求的主体都有一个计算字段,表示消息的长度。如果这不正确,服务器会将其视为无效请求并终止会话。

以下是应用程序中使用的几个示例URL。

     

/socket.io/?EIO=3&transport=polling&t=MJJR2dr

/socket.io/?EIO=3&transport=polling&t=MJJZbUa&sid=iUTykeQQumxFJgEJAABL

URL中的“sid”参数表示到服务器的单个连接流。如果发送了无效消息(在尝试破解时很常见),那么服务器将关闭整个会话,之后必须重新开始新会话。

给定请求的主体中含有一个字段,其中存放有效载荷的字节数。这类似于“Content-Length”HTTP header,只不过该字段的值近针对socket.io。例如,如果你要发送的有效载荷是“hello”,那么,相应的主体将是“5:hello”,Content-Length头部的值是7。其中,5表示字符串“hello”中的字母数量,而7则表示字符串“hello”中的字母数量以及socket.io添加到主体内的字符串“5:”中的字母数量之和。与往常一样,Burp将替我们更新Content-Length头部,因此,这件事情我们无需担心。但是,我还没有找到能够自动计算和包含有效载荷长度的好方法。更让人头疼的是,我发现socket.io竟然会在同一个HTTP请求中发送多条消息。由于每个消息都是一个封装后的WebSocket有效载荷,并且每个消息都有自己的长度,因此,最终看起来就像这样:“5:hello,4:john,3:doe”(实际的语法可能有所不同,这里只是便于演示)。计算长度时一旦出错,服务器就会将其作为无效消息拒绝,这样,我们就要重新开始了。

这是body的示例。这是Juice-Shop应用程序中的响应,请求的格式相同。注意,这里的“215”表示“:”之后的有效载荷的长度。

  215:42[“challenge solved”,{“key”:”zeroStarsChallenge”,”name”:”Zero Stars”,”challenge”:”Zero Stars (Give a devastating zero-star feedback to the store.)”,”flag”:”e958569c4a12e3b97f38bd05cac3f0e5a1b17142″,”hidden”:false}]

使用Burp宏能解决第一个问题。基本上,每次Burp在服务器拒绝消息时匹配,宏将自动建立新会话并用有效的“sid”更新原始请求。通过转到options->Sessions->Macros->Add来创建新宏。

建立新会话的URL只需省略“sid”参数。例如:

  /socket.io/?EIO=3&transport=polling&t=MJJJ4Ku

19.jpg

服务器响应包含一个全新的“sid”值以供使用。

20.jpg

接下来,单击“Configure item”按钮,并将参数名称命名为“sid”。然后,选择“Extract from regex group”选项,并使用如下所示的正则表达式。

  "sid"\:"(.*?)"

21.jpg

这时,配置窗口应如下所示:

22.jpg

会话处理规则

现在有了一个宏,我们需要一种方法来触发它。这就是Burp会话处理规则的用武之地。通过

  Project options->Sessions->Session Handling Rules->Add

为“Check session is valid”创建新的规则动作:

23.jpg

配置新规则操作如下:

24.jpg

25.jpg

按如下方式配blackhillsinfosec置新规则操作:最后,在完成新规则操作后,还需修改规则的范围。你可以在此处决定要应用此规则的位置。建议至少将它用于Repeater,这样就可以手动重复请求。

26.jpg

以下是我配置范围规则的方法。你可以更加具体地了解自己所需范围,但下面的选项应该适用于大多数情况。

27.jpg

这是在没有会话处理规则的情况下发出的请求:

28.jpg

这里是在会话处理规则生效后发出的相同请求:

29.jpg

*参考来源: blackhillsinfosec,FB小编Covfefe编译,转载请注明来自FreeBuf.COM

相关 [分析 渗透 websocket] 推荐:

看我如何分析并渗透WebSocket和Socket.io

- - FreeBuf互联网安全新媒体平台
WebSocket是一种允许浏览器和服务器建立单个TCP连接然后进行全双工异步通信的技术. 由于它允许实时更新,而浏览器也无需向后台发送数百个新的HTTP polling请求,所以对于web程序来说,WebSocket非常流行. 这对于测试者来说是不好的,因为对WebSocket工具的支持不像HTTP那样普遍,有时候会更加复杂.

WebSocket实现多屏互动的分析及方案

- - 腾讯ISUX – 社交用户体验设计
多屏互动事实上是一个比较宽泛的概念,通俗来讲就是用户在不同的终端上通过有线、无线的连接方式进行通信,可进行多媒体(音频,视频,图片)内容的传输,解析,展示,控制等一系列操作. 而随着WebSocket协议的诞生,不同端之间的网页互连也变得流行起来,这种基于WebSocket协议实现多屏互动在运营活动上的使用也使得运营页面的形式也变得更加多样和有趣.

WebSocket实战

- - 新浪UED
互联网发展到现在,早已超越了原始的初衷,人类从来没有像现在这样依赖过他;也正是这种依赖,促进了互联网技术的飞速发展. 而终端设备的创新与发展,更加速了互联网的进化;. WebSocket的前世今生. 为什么使用WebSocket. 搭建WebSocket服务器. 以上六点分为两大块,前3点侧重理论,主要让大家明白WebSocket是什么,而后3点则结合代码实战,加深对WebSocket的认知.

tomcat7之websocket

- - ITeye博客
从tomcat7.0.26之后开始支持websocket,建议大家使用tomcat7.0.30,期间版本的接口有一些改动. chrome默认支持websocket. 其他浏览器可能由于安全原因,默认是关闭的. // 与7.0.27不同的,Tomcat改变了createWebSocketInbound方法的定义,增加了一个HttpServletRequest参数.

基于Tomcat的WebSocket

- - ITeye博客
之前大概的看过WebSocket,当时Tomcat还不支持WebSocket,所以当时写了一篇基于Jetty的WebSocket实现,地址如下:. 现在Tomcat7.0.27发布了,从这个版本开始Tomcat就支持WebSocket了. Tomcat的WebSocket和Jetty的大致上差不多,大同小异,这里就简单的贴两个类吧:.

【转载】认识HTML5的WebSocket

- - HTML5研究小组
在HTML5规范中,我最喜欢的Web技术就是正迅速变得流行的WebSocket API. WebSocket提供了一个受欢迎的技术,以替代我们过去几年一直在用的Ajax技术. 这个新的API提供了一个方法,从客户端使用简单的语法 有效地推动消息到服务器. 让我们看一看HTML5的WebSocket API:它可用于客户端、服务器端.

反向Ajax,第2部分:WebSocket

- KnightE - 译言-电脑/网络/数码科技
来源Reverse Ajax, Part 2: WebSockets. 时至今日,用户期待的是可通过web访问快速、动态的应用. 这一文章系列展示了如何使用反向Ajax(Reverse Ajax)技术来开发事件驱动的web应用. 系列的第1部分介绍了反向Ajax、轮询(polling)、流(streaming)、Comet和长轮询(long polling).

htm5-websocket实现数据查询应用

- - 博客园_首页
在之前的文章讲述了使用Websocket调用远程方式的功能,在这基础我们可以简单地使用WebSocket进行数据处理方面的应用;只需要在方法执行相关的数据库操作返回即可,结合jeasyui库所提供丰富的控件进行数据应用处理变得非常简单的事情.下面使用jeasyui和WebSocket实现一个查询Northwind数据订单的应用案例..

七种WebSocket框架的性能比较

- - 鸟窝
前一篇文章 使用四种框架分别实现百万websocket常连接的服务器介绍了四种websocket框架的测试方法和基本数据. 最近我又使用几个框架实现了websocket push服务器的原型,并专门对这七种实现做了测试. 本文记录了测试结果和一些对结果的分析. 使用三台C3.4xlarge AWS服务器做测试.

使用nginx作为websocket的proxy server

- - CSDN博客推荐文章
WebSocket协议为创建客户端和服务器端需要实时双向通讯的webapp提供了一个选择. 其为HTML5的一部分,WebSocket相较于原来开发这类app的方法来说,其能使开发更加地简单. 大部分现在的浏览器都支持WebSocket,比如Firefox,IE,Chrome,Safari,Opera,并且越来越多的服务器框架现在也同样支持WebSocket.