De/construct ubnt discovery packets. Useful for spoofing ubnt discovery packets when on a VPN because this AmpliFi Wifi app is dumb and doesn't let you specify an IP address to connect to.
""" | |
De/construct ubnt discovery packets | |
references: | |
- https://github.com/nitefood/python-ubnt-discovery | |
- https://gist.github.com/trhura/5998584 | |
""" | |
from base64 import b64decode, b64encode | |
from enum import IntEnum | |
from construct import ( | |
this, | |
Byte, | |
Switch, | |
PaddedString, | |
Const, | |
Int16ub, | |
Enum, | |
Struct, | |
GreedyRange, | |
) | |
class FieldType(IntEnum): | |
UBNT_MAC = 0x01 | |
UBNT_MAC_AND_IP = 0x02 | |
UBNT_FIRMWARE = 0x03 | |
UBNT_IP = 0x04 | |
UBNT_UNKNOWN_2 = 0x0a | |
UBNT_RADIONAME = 0x0b | |
UBNT_MODEL_SHORT = 0x0c | |
UBNT_ESSID = 0x0d | |
UBNT_UNKNOWN_3 = 0x0e | |
UBNT_UNKNOWN_1 = 0x10 | |
UBNT_MODEL_FULL = 0x14 | |
DiscoveryField = Struct( | |
"type" / Enum(Byte, FieldType), | |
"len" / Int16ub, | |
"data" / Switch(this.type, { | |
"UBNT_FIRMWARE": Struct("firmware" / PaddedString(this._.len, 'ascii')), | |
"UBNT_RADIONAME": Struct("radio_name" / PaddedString(this._.len, 'ascii')), | |
"UBNT_MODEL_SHORT": Struct("model_short" / PaddedString(this._.len, 'ascii')), | |
"UBNT_MAC": Struct("mac" / Byte[6]), | |
"UBNT_IP": Struct("ip" / Byte[4]), | |
"UBNT_MAC_AND_IP": Struct( | |
"mac" / Byte[6], | |
"ip" / Byte[4], | |
), | |
}, default=Byte[this.len]), | |
) | |
DiscoveryPacket= Struct( | |
"magic" / Const(b'\x01\x00\x00'), | |
"len" / Byte, | |
"fields" / GreedyRange(DiscoveryField), | |
) | |
payload = bytearray(b64decode(b"AQAAZAwACEFGaS1SLUhECwANNSBHdXlzIDEgV2lmaQMAGUFGaS1SLjIuNy4wLjAtZzU1YWM5YmJkNWMBAAbwn8I5VR4OAAEDCgAEAAZybBAAAkHVAgAK8p/COVUewKi9AQQABMCovQE=")) | |
disc = DiscoveryPacket.parse(payload) | |
print(disc) | |
# This is some code for replacing the IP adddress with another. Useful to spoof | |
# a discovery packet when on a VPN. | |
# | |
# replacement_ip = bytearray([10, 0, 216, 98]) | |
# for f in disc.fields: | |
# f_type = int(f.type) | |
# if any((f_type == FieldType.UBNT_IP, | |
# f_type == FieldType.UBNT_MAC_AND_IP)): | |
# f.data.ip = replacement_ip | |
# | |
# packet = DiscoveryPacket.build(disc) | |
# | |
# print(DiscoveryPacket.parse(packet)) | |
# print(b64encode(packet)) |
$ ./venv/bin/python deconstruct_packet.py | |
Container: | |
magic = b'\x01\x00\x00' (total 3) | |
len = 100 | |
fields = ListContainer: | |
Container: | |
type = (enum) UBNT_MODEL_SHORT 12 | |
len = 8 | |
data = Container: | |
model_short = u'AFi-R-HD' (total 8) | |
Container: | |
type = (enum) UBNT_RADIONAME 11 | |
len = 13 | |
data = Container: | |
radio_name = u'5 Guys 1 Wifi' (total 13) | |
Container: | |
type = (enum) UBNT_FIRMWARE 3 | |
len = 25 | |
data = Container: | |
firmware = u'AFi-R.2.7.0.0-g55ac9bbd5c' (total 25) | |
Container: | |
type = (enum) UBNT_MAC 1 | |
len = 6 | |
data = Container: | |
mac = ListContainer: | |
240 | |
159 | |
194 | |
57 | |
85 | |
30 | |
Container: | |
type = (enum) UBNT_UNKNOWN_3 14 | |
len = 1 | |
data = ListContainer: | |
3 | |
Container: | |
type = (enum) UBNT_UNKNOWN_2 10 | |
len = 4 | |
data = ListContainer: | |
0 | |
6 | |
114 | |
108 | |
Container: | |
type = (enum) UBNT_UNKNOWN_1 16 | |
len = 2 | |
data = ListContainer: | |
65 | |
213 | |
Container: | |
type = (enum) UBNT_MAC_AND_IP 2 | |
len = 10 | |
data = Container: | |
mac = ListContainer: | |
242 | |
159 | |
194 | |
57 | |
85 | |
30 | |
ip = ListContainer: | |
192 | |
168 | |
189 | |
1 | |
Container: | |
type = (enum) UBNT_IP 4 | |
len = 4 | |
data = Container: | |
ip = ListContainer: | |
192 | |
168 | |
189 | |
1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment