PortSwigger——WebSockets vulnerabilitiesLab: Manipulating the WebSocket handshake to exploit vulnerabilitiesWebSocket 是如何建立连接的Handshake。服务器是如何根据 IP 对 WebSocket 进行封禁以及为什么可以绕过。第一步发送正常聊天消息Click Live chat and send a chat message.作用建立一个正常的 WebSocket 连接。浏览器会先发送GET /chat HTTP/1.1 Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: ... Sec-WebSocket-Version: 13服务器返回101 Switching Protocols此时 HTTP 协议升级成了 WebSocket。之后聊天内容都不会再走 HTTP而是走Client │ │ WebSocket Frame ▼ Server所以先发一条聊天消息是为了让 Burp 能抓到 WebSocket 数据。打开burp的拦截后给对方发一个信息第二步查看 WebSockets historyIn Burp Proxy, go to the WebSockets history tab这里不是 HTTP History。而是Proxy │ ├── HTTP history │ └── WebSockets history因为聊天内容已经不是 HTTP Request。例如hello实际上变成Text Frame helloBurp 会显示→ hello ← hello第三步Send to RepeaterRight-click → Send to Repeater为什么因为 Repeater 可以修改 WebSocket 消息无限重发不影响浏览器例如浏览器发的是hello在 Repeater 可以改成scriptalert(1)/script或者img src1 onerroralert(1)发送到repeater后结束刚才的拦截光放行是不行的之后repeater的右侧history中显示出了对方的回复client后即算操作正确第四步发送普通 XSSimg src1 onerroralert(1)为什么这里是在测试服务器有没有过滤 XSS。正常来说浏览器收到img src1 onerroralert(1)浏览器加载src1失败触发onerror执行alert(1)所以这是最经典的 XSS Payload。在repeater中发送xss攻击的代码发送后刷新live chat的页面后出现the address is blacklisted 就说明第一阶段的普通xss攻击成功了第五步攻击被拦截Observe that the attack has been blocked服务器检测到了onerror于是拒绝消息关闭 WebSocket例如Close Frame 1008 Policy Violation或者直接TCP FIN所以连接没了。第六步Reconnect点击Reconnect结果403或者Connection Failed为什么因为服务器已经把你的 IP 拉黑。例如服务器记录192.168.1.8 Status Blocked以后所有连接192.168.1.8 ↓ Reject所以连不上。第七步修改握手重点Lab 名字就是Manipulating the WebSocket handshake也就是修改第一次 Upgrade 请求。例如原来GET /chat HTTP/1.1 Upgrade: websocket修改成GET /chat HTTP/1.1 Upgrade: websocket X-Forwarded-For: 1.1.1.1为什么因为很多网站真实架构是Browser ↓ Nginx ↓ Tomcat真正客户端 IP通常来自X-Forwarded-For例如Client ↓ Nginx ↓ TomcatNginxX-Forwarded-For: 203.1.2.3Tomcat哦 客户端是 203.1.2.3如果服务器错误地信任客户端自己提供的X-Forwarded-For那么攻击者可以伪造 IP。例如X-Forwarded-For: 1.1.1.1服务器认为攻击者不是原来的 IP 允许连接实际上真实 IP 根本没变。所以这是IP Spoofing应用层伪造。注意这不是网络层真正修改 IP而是利用应用错误信任 HTTP 头。第八步重新连接成功因为服务器认为新 IP ↓ 1.1.1.1不是192.168.1.8于是101 Switching Protocols连接重新建立。打开burp的拦截后刷新刚才的live chat页面 在请求中加入我们新的ip地址例如1.1.1.1放行成功后会出现新的live chat页面 只是没了我们之前的聊天记录不要关闭拦截 往后我们每次放行一次该页面的请求时我们都得加入新的ip直至完成新的xss注入在repeater中重新连接第九步发送混淆 XSS官方给的是img src1 oNeRrOralert1为什么这样写普通onerror很多 WAFif payload contains onerror ↓ Block但是 HTML 属性大小写不敏感。所以oNeRrOr浏览器解析成onerror完全一样。因此oNeRrOr可以绕过一些大小写敏感的检测。另外alert1为什么不用alert(1)因为JavaScript 支持函数模板字符串例如alert1相当于alert([1])浏览器最后仍然会弹窗。很多过滤器只检查alert(因此alert就绕过去了。最终 Payloadimg src1 oNeRrOralert1浏览器仍然执行图片加载失败 ↓ 触发 onerror ↓ 执行 alert但服务器如果只做简单字符串匹配就可能没有识别出来。除了以上官方的回答外 我们也有其它的代码方案iframe srcjAvAsCripT:alert1/iframe整个 Lab 的流程图浏览器 │ │ 建立 WebSocket ▼ Server │ │ 发送普通 XSS ▼ WAF 检测到 onerror │ ├── 拒绝消息 └── 封禁 IP │ ▼ Reconnect 失败 │ ▼ 修改握手请求 X-Forwarded-For: 1.1.1.1 │ ▼ 服务器误认为新 IP │ ▼ 连接成功 │ ▼ 发送混淆 Payload img src1 oNeRrOralert1 │ ▼ 绕过简单过滤 │ ▼ XSS 成功