huge commit

This commit is contained in:
2026-03-09 21:44:25 +01:00
parent ab2e537520
commit d1017bae51
441 changed files with 3438154 additions and 1363 deletions

View File

@@ -0,0 +1 @@
3.13

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env python3
# pip install pycryptodome
import hashlib
from Crypto.Cipher import AES
AES_KEK_GENERATION_SOURCE = bytes.fromhex("4d870986c45d20722fba1053da92e8a9")
AES_KEY_GENERATION_SOURCE = bytes.fromhex("89615ee05c31b6805fe58f3da24f7aa8")
# Advertisement frame input key (from kinnay wiki)
ADV_INPUT_KEY = bytes.fromhex("191884743e24c77d87c69e4207d0c438")
# Data frame input key
DATA_INPUT_KEY = bytes.fromhex("f1e7018419a84f711da714c2cf919c9c")
def aes_unwrap(data: bytes, key: bytes) -> bytes:
return AES.new(key, AES.MODE_ECB).decrypt(data)
def derive_key(master_key_00: bytes, input_key: bytes, input_buffer: bytes) -> bytes:
kek = aes_unwrap(AES_KEK_GENERATION_SOURCE, master_key_00)
kek2 = aes_unwrap(input_key, kek)
kek3 = aes_unwrap(AES_KEY_GENERATION_SOURCE, kek2)
hash16 = hashlib.sha256(input_buffer).digest()[:16]
return aes_unwrap(hash16, kek3)
def decrypt_advertisement(master_key_00: bytes, raw_frame: bytes):
# Advertisement payload starts at byte 0x45 (after radiotap + 802.11 + action header)
adv_payload = raw_frame[0x45:]
session_info = adv_payload[0x00:0x20] # 32 bytes, plaintext
nonce_bytes = adv_payload[0x24:0x28] # 4-byte nonce
encrypted = adv_payload[0x28:] # hash + advertisement data (encrypted)
# Derive advertisement decryption key using session_info as input buffer
adv_key = derive_key(master_key_00, ADV_INPUT_KEY, session_info)
# AES-CTR: nonce is 4 bytes, padded to 16 with zeros, counter starts at 1
ctr_nonce = nonce_bytes + b'\x00' * 8 # 12-byte nonce
cipher = AES.new(adv_key, AES.MODE_CTR, nonce=ctr_nonce, initial_value=1)
decrypted = cipher.decrypt(encrypted)
# Layout: 32-byte hash, then advertisement data
# Advertisement data[0x00:0x10] = server random
server_random = decrypted[32:48]
return session_info, server_random
def derive_data_key(master_key_00: bytes, server_random: bytes, passphrase: str) -> bytes:
input_buffer = server_random + passphrase.encode()
return derive_key(master_key_00, DATA_INPUT_KEY, input_buffer)
if __name__ == "__main__":
master_key_00 = bytes.fromhex("c2caaff089b9aed55694876055271c7d")
passphrase = "LunchPack2DefaultPhrase"
raw_frame = bytes.fromhex(
"000021002a4008a0200800a02008000000009e098004e6000000070003de00e601d0000000ffffffffffff98b6e9038247ffffffffffffe0cb7f0022aa040001010000000001009b90006dc000000000010000000004dd5b26140f143755d0adea03aad9b004020500217be113cb40f9c24b5707e06d1eab6454724bed49112bb42b9634816fd1583b0ea1ad6a47c1df57f4fb07b2c60cd447707a0c02e3f4b7f238559e8493a42814071c0423ac6d5c41767c3573e7c4dc406ba6e81a7a6c0a30c6f99a1a7b29e42c6f0cefd4add4436c68fc622a5a27ae772e3b5959d785bd6af34f8f01d069385efb2d75281a69d7f4e2b0e42cf3fdc5d9ba7fef1b7484a77c38437e4e0b22b1d31d9f6cbacfd508e7dc85d1902094102a7296672d4bd1b3481cd1a137228fecb22c1798fb828f21a8c785f4487f0d02f8e0fb64b19f967c606f048cda44673b940444c3e8ead46871ef72ba21b6786739948b6bdb04be9ef3612207f5be747d08789ad4c98a4d6765050661f96cfbc36f771d3eb5738b164ae167297c34e1ea23fb90f11826e6bd41182160a9b38168b8a7a4473b9b016322bce2bb4715d1b940357fc277c71121fb05cacc14560a3e459dcc631054d95908b178a5a7a2387922147f8cc90a91875d337d24c7ac3fcdb8c4c8c0bd18722d23f77a2aafebbb4dc458d725491875e40c21605ab76ff23bf66572d0898c9b002e4576d9552471599a39438f7ffe053f9861a7342f4afecc0020c788b69b723b03a6a44f0f15cfc2b806e70d738584ede19fd3324939ad3075a309247be67d7389bb1ff6f9c89ba801fe942c6134553315440f19702e9ad54f8b981d668566bc349dbedff418dadcc21bf70cdf7342addcba7f639b347be49d696d993fe67ca9537b52f153ac80dd657b9006a637b69e0ac9b6bb4e47c7eaad76b162710c1ebaa23664e564aed69ef6549cecb4606b957bdb2fba5c46399faf9bc0bc0e9aa5aaec6c9c97b7c52b10103529dcc7ee5252a83b705981a8ebbc4452405eec83f7077f2616ea359d327daf5f7ca53aab6da258d9fd08d719ef60315d1ab1d678ca07cc0344e88e9bec226332b105877109c297bf8d0c7c87337f422031488883cf24ea44b40783ad22bdd67bceb97783056107e666cd34f5047d23a4e1d226f8896285ad2f7b92767a84a7dfefecad281f759ac8975072687d1cc175672c92a87c1fb8f6eae33c80a1609015f9c12e799c548369fe5a25da28009330732ac5b73ece4805c9ffc3a10a22569630c410bcd22d65965927c292359c3dcf69dc7e39a1cf4b60afc65b6a95ab501c63ece017b8f68c3fa98fbf09236ada72214f2d560ac7da7b5720bf9eedcf1377072506259968c1c961b0253743630bb698003f61fa32bd712b49bb6a0daff159eccc7d0a19967ffc1fb01a861fdd076925bcab7d171c4dd561c6988a37d3b609e14550e5da78c0859ed2dbf71e43d5d681ce09be726b224b15a444acb90962d3d22d30006a1da94f20bfcf9f7a4977b98026a6d250d879c2fec5f8849c54896600fc4252bcbf188c3c1c2ecb872ece09d6b8ad707567630f8aad89982bf0d5186b6d91ee4ffb236b5dbb75a79610ac9a24c4c70a40e011f74c1de15cb31381819458f4d2215e6dc554833aaec12a0847a779b1707e6b79d82cc9ce90d36b15805a4c056ead365bf3587423e6adff5a402c69772c98ef33905848c51e897b342c993c013b74b03cd11773e8ee18a750faa68833d360992e9c9f3fdc2282736ecc361886900349bb90f47b382b78b10847ef57a4d6fb499dcbb401fc1e346f41069f8ede4f00ffc3d5a4efa085f3a2d3c9630e643c03bec4536f883f44ae7304d94e8b100e0ebc414a86e17fda4b742fba5f34ad2c397da51972208bb89f6a6ea8927103a305b467d90e8bb70b7bbaeb0210d729f7aba685d7f543ed21925f5ae3e82362c6daa6db4c5d05187e10741debc4273bdb710af4195fa6ed33a8ff62ec39de4e"
)
session_info, server_random = decrypt_advertisement(master_key_00, raw_frame)
print(f"Session info: {session_info.hex()}")
print(f"Server random: {server_random.hex()}")
data_key = derive_data_key(master_key_00, server_random, passphrase)
print(f"Data frame key: {data_key.hex()}")

View File

@@ -0,0 +1,38 @@
#!/usr/bin/env python3
from Crypto.Cipher import AES
from scapy.all import rdpcap
from scapy.compat import raw
DATA_FRAME_KEY = bytes.fromhex("0f8278e73cb3d132d33fb84bea24288f")
def decrypt_data_frame(raw_frame: bytes, key: bytes) -> bytes:
# Data payload starts at 0x45 same as advertisement
payload = raw_frame[0x45:]
# Same nonce layout: 4-byte nonce at offset 0x24, encrypted data after 0x28
nonce_bytes = payload[0x24:0x28]
encrypted = payload[0x28:]
ctr_nonce = nonce_bytes + b'\x00' * 8
cipher = AES.new(key, AES.MODE_CTR, nonce=ctr_nonce, initial_value=1)
return cipher.decrypt(encrypted)
packets = rdpcap("./capture.pcapng")
for i, pkt in enumerate(packets):
raw_bytes = raw(pkt)
# Skip packets that are too short or look like advertisement frames
# You may need to adjust this filter for your capture
if len(raw_bytes) < 0x45 + 0x28:
continue
try:
decrypted = decrypt_data_frame(raw_bytes, DATA_FRAME_KEY)
print(f"[Packet {i}] Decrypted ({len(decrypted)} bytes):")
print(f" type: {decrypted[0:2].hex()}")
print(f" length: {int.from_bytes(decrypted[2:4], 'little')}")
print(f" payload: {decrypted[4:].hex()}")
print()
except Exception as e:
print(f"[Packet {i}] Failed: {e}")

View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python3
# pip install pycryptodome
import hashlib
from Crypto.Cipher import AES
# --- Constants (public, from prod.keys) ---
AES_KEK_GENERATION_SOURCE = bytes.fromhex("4d870986c45d20722fba1053da92e8a9")
AES_KEY_GENERATION_SOURCE = bytes.fromhex("89615ee05c31b6805fe58f3da24f7aa8")
# LDN data frame input key (from kinnay's wiki)
LDN_INPUT_KEY = bytes.fromhex("f1e7018419a84f711da714c2cf919c9c")
def aes_unwrap(wrapped_key: bytes, wrap_key: bytes) -> bytes:
"""Single AES-128 block decryption (ECB)."""
return AES.new(wrap_key, AES.MODE_ECB).decrypt(wrapped_key)
def derive_ldn_key(master_key_00: bytes, server_random: bytes, passphrase: str) -> bytes:
"""
Derives the AES-CTR key used to encrypt LDN data frames.
Steps follow the LDN Protocol wiki exactly.
"""
# Step 1: decrypt aes_kek_generation_source with master_key_00
kek = aes_unwrap(AES_KEK_GENERATION_SOURCE, master_key_00)
# Step 2: decrypt the LDN input key with the result
kek2 = aes_unwrap(LDN_INPUT_KEY, kek)
# Step 3: decrypt aes_key_generation_source with the result
kek3 = aes_unwrap(AES_KEY_GENERATION_SOURCE, kek2)
# Step 4: build the input buffer = server_random + passphrase bytes
passphrase_bytes = passphrase.encode("utf-8")
input_buffer = server_random + passphrase_bytes
# Hash it, take first 16 bytes, decrypt with kek3
hash_bytes = hashlib.sha256(input_buffer).digest()[:16]
data_key = aes_unwrap(hash_bytes, kek3)
return data_key
if __name__ == "__main__":
# --- Fill these in ---
# Your master_key_00 from prod.keys
master_key_00 = bytes.fromhex("c2caaff089b9aed55694876055271c7d")
# 16-byte server random from the LDN advertisement frame in Wireshark
server_random = bytes.fromhex("YOUR_SERVER_RANDOM_HERE")
passphrase = "LunchPack2DefaultPhrase"
key = derive_ldn_key(master_key_00, server_random, passphrase)
print(f"Derived AES-CTR key: {key.hex()}")

View File

@@ -0,0 +1,10 @@
[project]
name = "slippery-slope"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"pycryptodome>=3.23.0",
"scapy>=2.7.0",
]

View File

@@ -0,0 +1,57 @@
version = 1
revision = 3
requires-python = ">=3.13"
[[package]]
name = "pycryptodome"
version = "3.23.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" },
{ url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" },
{ url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" },
{ url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" },
{ url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" },
{ url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" },
{ url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" },
{ url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" },
{ url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" },
{ url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" },
{ url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" },
{ url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" },
{ url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" },
{ url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" },
{ url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" },
{ url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" },
{ url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" },
{ url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" },
{ url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" },
{ url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" },
{ url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" },
{ url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" },
]
[[package]]
name = "scapy"
version = "2.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/82/97/7caec64f05eae3d305d83e7cce1ef2f337710513b89efb334f7278202e79/scapy-2.7.0.tar.gz", hash = "sha256:bfc1ef1b93280aea1ddee53be7f74232aa28ac3d891244d41ee85200d24aa446", size = 2412897, upload-time = "2025-12-26T22:10:53.359Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f0/6f/bd32e5e8adc391063858da17271bb444e4b009842cffa593bca8b2b78af7/scapy-2.7.0-py3-none-any.whl", hash = "sha256:eb22786da92be6fd8e5c694ae5595e4f5b9ac1f4364c9c45986844f3e3063561", size = 2590982, upload-time = "2025-12-26T22:07:48.941Z" },
]
[[package]]
name = "slippery-slope"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "pycryptodome" },
{ name = "scapy" },
]
[package.metadata]
requires-dist = [
{ name = "pycryptodome", specifier = ">=3.23.0" },
{ name = "scapy", specifier = ">=2.7.0" },
]