-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwps.py
407 lines (344 loc) · 11 KB
/
wps.py
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# Impacket - Collection of Python classes for working with network protocols.
#
# SECUREAUTH LABS. Copyright (C) 2021 SecureAuth Corporation. All rights reserved.
#
# This software is provided under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Description:
# WPS packets
#
# Author:
# Aureliano Calvo
#
import array
import struct
from impacket.ImpactPacket import array_tobytes
from impacket.helper import ProtocolPacket, Byte, Bit
from functools import reduce
class ArrayBuilder(object):
def from_ary(self, ary):
return ary
def to_ary(self, value):
return array.array("B", value)
class ByteBuilder(object):
def from_ary(self, ary):
return ary[0]
def to_ary(self, value):
return array.array('B', [value])
class StringBuilder(object):
def from_ary(self, ary):
return array_tobytes(ary)
def to_ary(self, value):
return array.array('B', value)
class NumBuilder(object):
"""Converts back and forth between arrays and numbers in network byte-order"""
def __init__(self, size):
"""size: number of bytes in the field"""
self.size = size
def from_ary(self, ary):
if len(ary) != self.size:
raise Exception("Expected %s size but got %s" % (self.size, len(ary)))
return reduce( lambda ac, x: ac * 256 + x, ary, 0)
def to_ary(self, value0):
value = value0
rv = array.array('B')
for _ in range(self.size):
value, mod = divmod(value, 256)
rv.append(mod)
if value != 0:
raise Exception("%s is too big. Max size: %s" % (value0, self.size))
rv.reverse()
return rv
class TLVContainer(object):
def builder(self, kind):
return self.builders.get(kind, self.default_builder)
def from_ary(self, ary):
i = 0
while i<len(ary):
kind = self.ary2n(ary, i)
length = self.ary2n(ary, i+2)
i+=4
value = ary[i:i+length]
self.elems.append((kind, value))
i += length
return self
def __init__(self, builders, default_builder = ArrayBuilder(), descs=None):
self.builders = builders
self.default_builder = default_builder
self.elems = []
self.descs = descs or {}
def append(self, kind, value):
self.elems.append((kind, self.builder(kind).to_ary(value)))
def __iter__(self):
return ((k, self.builder(k).from_ary(v)) for k,v in self.elems)
def all(self, kind):
return [e[1] for e in self if e[0] == kind]
def __contains__(self, kind):
return len(self.all(kind)) != 0
def first(self, kind):
return self.all(kind)[0]
def to_ary(self):
ary = array.array('B')
for k,v in self.elems:
ary.extend(self.n2ary(k))
ary.extend(self.n2ary(len(v)))
ary.extend(v)
return ary
def get_packet(self):
return array_tobytes(self.to_ary())
def set_parent(self, my_parent):
self.__parent = my_parent
def parent(self):
return self.__parent
def n2ary(self, n):
return array.array("B", struct.pack(">H",n))
def ary2n(self, ary, i=0):
return struct.unpack(">H", array_tobytes(ary[i:i+2]))[0]
def __repr__(self):
def desc(kind):
return self.descs[kind] if kind in self.descs else kind
return "<TLVContainer %s>" % repr([(desc(k), self.builder(k).from_ary(v)) for (k,v) in self.elems])
def child(self):
return None
class SCElem(object):
#Data elements as defined in section 11 of the WPS 1.0h spec.
AP_CHANNEL = 0x1001
ASSOCIATION_STATE = 0x1002
AUTHENTICATION_TYPE = 0x1003
AUTHENTICATION_TYPE_FLAGS = 0x1004
AUTHENTICATOR = 0x1005
CONFIG_METHODS = 0x1008
CONFIGURATION_ERROR = 0x1009
CONFIRMATION_URL4 = 0x100A
CONFIRMATION_URL6 = 0x100B
CONNECTION_TYPE = 0X100C
CONNECTION_TYPE_FLAGS = 0X100D
CREDENTIAL = 0X100E
DEVICE_NAME = 0x1011
DEVICE_PASSWORD_ID = 0x1012
E_HASH1 = 0x1014
E_HASH2 = 0x1015
E_SNONCE1 = 0x1016
E_SNONCE2 = 0x1017
ENCRYPTED_SETTINGS = 0x1018
ENCRYPTION_TYPE = 0X100F
ENCRYPTION_TYPE_FLAGS = 0x1010
ENROLLEE_NONCE = 0x101A
FEATURE_ID = 0x101B
IDENTITY = 0X101C
INDENTITY_PROOF = 0X101D
KEY_WRAP_AUTHENTICATOR = 0x101E
KEY_IDENTIFIER = 0X101F
MAC_ADDRESS = 0x1020
MANUFACTURER = 0x1021
MESSAGE_TYPE = 0x1022
MODEL_NAME = 0x1023
MODEL_NUMBER = 0x1024
NETWORK_INDEX = 0x1026
NETWORK_KEY = 0x1027
NETWORK_KEY_INDEX = 0x1028
NEW_DEVICE_NAME = 0x1029
NEW_PASSWORD = 0x102A
OOB_DEVICE_PASSWORD = 0X102C
OS_VERSION= 0X102D
POWER_LEVEL = 0X102F
PSK_CURRENT = 0x1030
PSK_MAX = 0x1031
PUBLIC_KEY = 0x1032
RADIO_ENABLED = 0x1033
REBOOT = 0x1034
REGISTRAR_CURRENT = 0x1035
REGISTRAR_ESTABLISHED = 0x1036
REGISTRAR_LIST = 0x1037
REGISTRAR_MAX = 0x1038
REGISTRAR_NONCE = 0x1039
REQUEST_TYPE = 0x103A
RESPONSE_TYPE = 0x103B
RF_BANDS = 0X103C
R_HASH1 = 0X103D
R_HASH2 = 0X103E
R_SNONCE1 = 0X103F
R_SNONCE2 = 0x1040
SELECTED_REGISTRAR = 0x1041
SERIAL_NUMBER = 0x1042
WPS_STATE = 0x1044
SSID = 0x1045
TOTAL_NETWORKS = 0x1046
UUID_E = 0x1047
UUID_R = 0x1048
VENDOR_EXTENSION = 0x1049
VERSION = 0x104A
X_509_CERTIFICATE_REQUEST = 0x104B
X_509_CERTIFICATE = 0x104C
EAP_IDENTITY = 0x104D
MESSAGE_COUNTER = 0x104E
PUBLIC_KEY_HASH = 0x104F
REKEY_KEY = 0x1050
KEY_LIFETIME = 0x1051
PERMITTED_CONFIG_METHODS = 0x1052
SELECTED_REGISTRAR_CONFIG_METHODS= 0x1053
PRIMARY_DEVICE_TYPE = 0x1054
SECONDARY_DEVICE_TYPE_LIST = 0x1055
PORTABLE_DEVICE = 0x1056
AP_SETUP_LOCKED = 0x1057
APPLICATION_EXTENSION = 0x1058
EAP_TYPE = 0x1059
INITIALIZATION_VECTOR = 0x1060
KEY_PROVIDED_AUTOMATICALLY = 0x1061
_802_1X_ENABLED = 0x1062
APP_SESSION_KEY = 0x1063
WEP_TRANSMIT_KEY = 0x1064
class MessageType(object):
"""Message types according to WPS 1.0h spec, section 11"""
BEACON = 0x01
PROBE_REQUEST = 0x02
PROBE_RESPONSE = 0x03
M1 = 0x04
M2 = 0x05
M2D = 0x06
M3 = 0x07
M4 = 0x08
M5 = 0x09
M6 = 0x0A
M7 = 0x0B
M8 = 0x0C
WSC_ACK = 0x0D
WSC_NACK = 0x0E
WSC_DONE = 0x0F
class AuthTypeFlag(object):
OPEN = 0x0001
WPAPSK = 0x0002
SHARED = 0x0004
WPA = 0x0008
WPA2 = 0x0010
WPA2PSK = 0x0020
AuthTypeFlag_ALL = AuthTypeFlag.OPEN | \
AuthTypeFlag.WPAPSK | \
AuthTypeFlag.SHARED | \
AuthTypeFlag.WPA | \
AuthTypeFlag.WPA2 | \
AuthTypeFlag.WPA2PSK
class EncryptionTypeFlag(object):
NONE = 0x0001
WEP = 0x0002
TKIP = 0x0004
AES = 0x0008
EncryptionTypeFlag_ALL = EncryptionTypeFlag.NONE | EncryptionTypeFlag.WEP | EncryptionTypeFlag.TKIP | EncryptionTypeFlag.AES
class ConnectionTypeFlag(object):
ESS = 0x01
IBSS = 0x02
class ConfigMethod(object):
USBA = 0x0001
ETHERNET = 0x0002
LABEL = 0x0004
DISPLAY = 0x0008
EXT_NFC_TOKEN = 0x0010
INT_NFC_TOKEN = 0x0020
NFC_INTERFACE = 0x0040
PUSHBUTTON = 0x0080
KEYPAD = 0x0100
class OpCode(object):
WSC_START = 0x01
WSC_ACK = 0x02
WSC_NACK = 0x03
WSC_MSG = 0x04
WSC_DONE = 0x05
WSC_FRAG_ACK = 0x06
class AssocState(object):
NOT_ASSOC = 0
CONN_SUCCESS = 1
CFG_FAILURE = 2
FAILURE = 3,
IP_FAILURE = 4
class ConfigError(object):
NO_ERROR = 0
OOB_IFACE_READ_ERROR = 1
DECRYPTION_CRC_FAILURE = 2
_24_CHAN_NOT_SUPPORTED = 3
_50_CHAN_NOT_SUPPORTED = 4
SIGNAL_TOO_WEAK = 5
NETWORK_AUTH_FAILURE = 6
NETWORK_ASSOC_FAILURE = 7
NO_DHCP_RESPONSE = 8
FAILED_DHCP_CONFIG = 9
IP_ADDR_CONFLICT = 10
NO_CONN_TO_REGISTRAR = 11
MULTIPLE_PBC_DETECTED = 12
ROGUE_SUSPECTED = 13
DEVICE_BUSY = 14
SETUP_LOCKED = 15
MSG_TIMEOUT = 16
REG_SESS_TIMEOUT = 17
DEV_PASSWORD_AUTH_FAILURE = 18
class DevicePasswordId(object):
DEFAULT = 0x0000
USER_SPECIFIED = 0x0001
MACHINE_SPECIFIED = 0x0002
REKEY = 0x0003
PUSHBUTTON = 0x0004
REGISTRAR_SPECIFIED = 0x0005
class WpsState(object):
NOT_CONFIGURED = 0x01
CONFIGURED = 0x02
class SimpleConfig(ProtocolPacket):
"For now, it supports Simple configs with the bits more_fragments and length_field not set"
header_size = 2
tail_size = 0
op_code = Byte(0)
flags = Byte(1)
more_fragments = Bit(1, 0)
length_field = Bit(1,1)
BUILDERS = {
SCElem.CONNECTION_TYPE: ByteBuilder(),
SCElem.CONNECTION_TYPE_FLAGS: ByteBuilder(),
SCElem.VERSION: ByteBuilder(),
SCElem.MESSAGE_TYPE: ByteBuilder(),
SCElem.NETWORK_INDEX: ByteBuilder(),
SCElem.NETWORK_KEY_INDEX: ByteBuilder(),
SCElem.POWER_LEVEL: ByteBuilder(),
SCElem.PSK_CURRENT: ByteBuilder(),
SCElem.PSK_MAX: ByteBuilder(),
SCElem.REGISTRAR_CURRENT: ByteBuilder(),
SCElem.REGISTRAR_MAX: ByteBuilder(),
SCElem.REQUEST_TYPE: ByteBuilder(),
SCElem.RESPONSE_TYPE: ByteBuilder(),
SCElem.RF_BANDS: ByteBuilder(),
SCElem.WPS_STATE: ByteBuilder(),
SCElem.TOTAL_NETWORKS: ByteBuilder(),
SCElem.VERSION: ByteBuilder(),
SCElem.WEP_TRANSMIT_KEY: ByteBuilder(),
SCElem.CONFIRMATION_URL4: StringBuilder(),
SCElem.CONFIRMATION_URL6: StringBuilder(),
SCElem.DEVICE_NAME: StringBuilder(),
SCElem.IDENTITY: StringBuilder(),
SCElem.MANUFACTURER: StringBuilder(),
SCElem.MODEL_NAME: StringBuilder(),
SCElem.MODEL_NUMBER: StringBuilder(),
SCElem.NEW_DEVICE_NAME: StringBuilder(),
SCElem.NEW_PASSWORD: StringBuilder(),
SCElem.SERIAL_NUMBER: StringBuilder(),
SCElem.EAP_IDENTITY: StringBuilder(),
SCElem.NETWORK_KEY: StringBuilder(),
SCElem.AP_CHANNEL: NumBuilder(2),
SCElem.ASSOCIATION_STATE: NumBuilder(2),
SCElem.AUTHENTICATION_TYPE: NumBuilder(2),
SCElem.AUTHENTICATION_TYPE_FLAGS: NumBuilder(2),
SCElem.CONFIG_METHODS: NumBuilder(2),
SCElem.CONFIGURATION_ERROR: NumBuilder(2),
SCElem.DEVICE_PASSWORD_ID: NumBuilder(2),
SCElem.ENCRYPTION_TYPE: NumBuilder(2),
SCElem.ENCRYPTION_TYPE_FLAGS: NumBuilder(2),
SCElem.MESSAGE_COUNTER: NumBuilder(8),
SCElem.KEY_LIFETIME: NumBuilder(4),
SCElem.PERMITTED_CONFIG_METHODS: NumBuilder(2),
SCElem.SELECTED_REGISTRAR_CONFIG_METHODS: NumBuilder(2),
SCElem.PUBLIC_KEY: NumBuilder(192),
}
@classmethod
def build_tlv_container(cls):
return TLVContainer(
builders=SimpleConfig.BUILDERS,
descs = dict( (v,k) for (k,v) in SCElem.__dict__.items() )
)