Skip to content

Instantly share code, notes, and snippets.

@jbott
Last active June 12, 2022 19:07
Show Gist options
  • Save jbott/f4fba00e938b93c1282ac61ae772bf5c to your computer and use it in GitHub Desktop.
Save jbott/f4fba00e938b93c1282ac61ae772bf5c to your computer and use it in GitHub Desktop.
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