Posted onInctfDisqus: Word count in article: 581Reading time ≈2 mins.
1
Our WiFi keeps disconnecting. We captured wireless traffic to try and figure out what’s happening, but it’s all temporal zeros to us! I think someone is trying to exploit a WiFi vulnerability.. Can you decrypt the traffic and gain access to the flag?
The hint "temporal zeros" and the context of a WiFi vulnerability
strongly suggest the KRACK (Key Reinstallation Attack),
specifically CVE-2017-13077.
Vulnerability Analysis: Why
"Zeros"?
In a standard WPA2 4-way handshake, the client and AP negotiate a
PTK (Pairwise Transient Key). KRACK works by
intercepting and replaying Message 3 of the handshake, forcing the
client to reinstall an already in-use key. This resets nonces (packet
numbers) and replay counters.
For certain versions of wpa_supplicant (notably 2.4 and
2.5), a critical implementation bug exists: when the key is reinstalled,
the Temporal Key (TK) is not just reused, but
cleared to all zeros.
The captured 802.11 CCMP packets are encrypted using a
16-byte key of \x00 values.
The WPA2 4-way Handshake &
PTK
Message 1: AP sends a random number
(ANonce) to the Client.
Message 2: Client generates its own random number
(SNonce), derives the PTK using both Nonces, and sends
SNonce to the AP.
Message 3: AP derives the same PTK, sends the Group
Temporal Key (GTK), and instructs the Client to install the PTK.
Message 4: Client confirms installation with an
ACK.
The KRACK attack manipulates Message 3 to trigger the "all-zero" TK
bug.
Decryption Methods
Method 1: Wireshark GUI
If you prefer a visual approach, you can configure Wireshark to
decrypt the traffic using the zeroed key:
Open Preferences
(Ctrl + Shift + P).
Go to Protocols -> IEEE 802.11.
Check "Enable decryption".
Click "Edit..." next to Decryption keys.
Add a new key:
Key type: tk
Key: 00000000000000000000000000000000
(32 zeros)
Method 2: Scapy Script (CLI)
The following script manually reconstructs the CCM Nonce and decrypts
the packets using the zeroed Temporal Key.
#!/usr/bin/env python3 import glob import os from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa from scapy.allimport * from scapy.layers.tls.allimport TLS from scapy.layers.tls.cert import Cert from scapy.layers.tls.handshake import TLSCertificate
defextract_certs_from_pcap(pcap_path): """Extracts TLS certificates from a PCAP file.""" packets = rdpcap(pcap_path) cert_list = []
for pkt in packets: if pkt.haslayer(Raw): raw = pkt[Raw].load try: tls_parsed = TLS(raw) tls_cert_layer = tls_parsed.getlayer(TLSCertificate) if tls_cert_layer: for _, x509_wrapper in tls_cert_layer.certs: cert_list.append(x509_wrapper) print(f"[+] Extracted Certificate: {x509_wrapper.subject}") except Exception: continue return cert_list
defget_rsa_modulus(cert_obj): """Extracts the RSA modulus from a Scapy Cert object.""" try: ifnotisinstance(cert_obj, Cert): returnNone pubkey_bytes = cert_obj.pubKey.der public_key = serialization.load_der_public_key(pubkey_bytes)
ifisinstance(public_key, rsa.RSAPublicKey): return public_key.public_numbers().n except Exception as e: print(f"[-] Error parsing public key: {e}") returnNone
deffind_matching_key(target_modulus, keys_directory): """Finds a PEM private key in a directory matching the given modulus.""" print(f"[*] Searching for matching key in {keys_directory}...")
for key_file in glob.glob(os.path.join(keys_directory, "*")): try: withopen(key_file, "rb") as f: private_key = serialization.load_pem_private_key( f.read(), password=None, backend=default_backend() )
Posted onInctfDisqus: Word count in article: 246Reading time ≈1 mins.
An encryption service encrypts plaintext, but blocks encryption of
the impossible_flag_user string. Exploit the ECB mode
implementation to forge an encrypted token that decrypts to this
forbidden value.
Vulnerability
The service uses AES in ECB mode, which has critical
weakness: identical plaintext blocks produce identical ciphertext
blocks. By crafting specific payloads, we can:
Encrypt the first 16 bytes of the target string
Encrypt padding-aligned subsequent bytes
Concatenate the cipher blocks to forge a valid token
Exploit Strategy
The target user is: impossible_flag_user (23 bytes)
Block 1: Encrypt impossible_flag_ (16
bytes) → get first cipher block
Block 2: Encrypt user + PKCS#7 padding
→ get second cipher block
Combine: Concatenate blocks to form forged token →
decrypt equals target
Posted onInctfDisqus: Word count in article: 175Reading time ≈1 mins.
Socket challenge requiring automation to solve 500 arithmetic
problems programmatically. Use Python with pwntools to interface with
the remote service and automate the solution.
Key Considerations
Library: pwntools for socket communication
Custom delimiter: Uses \r\n instead of
standard \n
Approach: Parse math expressions dynamically and
compute answers
Posted onInctfDisqus: Word count in article: 1.2kReading time ≈4 mins.
Challenge Description
1 2 3
Our web server was compromised again and we aren't really sure what the attacker was doing. Luckily, we only use HTTP and managed to capture network traffic during the attack! Can you figure out what the attacker was up to?
We start by analyzing the PCAP file to identify interesting HTTP
interactions. Using a simple Scapy script, we can filter for
200 OK responses to see what the server was returning.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#!/usr/bin/env python3 from scapy.allimport *
PCAP_FILE = "web_shell.pcap"
packages = rdpcap(PCAP_FILE) for i, p inenumerate(packages): if p.haslayer(Raw): raw = p[Raw].load ifb"200 OK"in raw: try: print(f"[*] Packet {i+1} | Length: {len(raw)}") print(raw.decode()) print("-" * 20) except: continue
In the output, we notice a file upload form and a confirmation that
owned.php was uploaded:
1 2 3 4 5 6 7 8 9 10 11 12
[*] Packet 16640 HTTP/1.1200 OK ... <body> <form enctype="multipart/form-data" action="uploader.php" method="POST"> <p>Upload your file</p> <input type="file" name="uploaded_file"></input><br /> <input type="submit" value="Upload"></input> </form> </body> </html> The file owned.php has been uploaded
Checking the preceding packets (around index 16638), we find the
content of the uploaded owned.php.
2. Analyzing the Malicious
Web Shell
The uploaded file owned.php contains an obfuscated PHP
script.
By removing the noise (replacing [Z and
eq), we can reconstruct the logic. It's a sophisticated web
shell (similar to Behinder or Godzilla) that uses XOR encryption and
Zlib compression for C2 traffic.
Now that we have the key (81aebe18) and the protocol
markers, we can decrypt the subsequent traffic. We notice the attacker
is executing commands like ls and xxd to read
a file named y_flag_here.txt one byte at a time.
Example of a decrypted request:
chdir('/var/www/html/uploads');@error_reporting(0);@system('xxd -p -l1 -s31 ../y_flag_here.txt 2>&1');
4. Automated Flag
Reconstruction
To get the full flag, we need to iterate through all packets, decrypt
the requests to find the offset (-s parameter in
xxd), and decrypt the responses to find the hex value of
the character at that offset.
#!/usr/bin/env python3 """ Scapy HTTP/Webshell Traffic Analyzer ------------------------------------ A specialized utility for extracting and decrypting payloads from PCAP files, targeting traffic typical of PHP webshells (e.g., Behinder, AntSword). Includes logic for XOR decryption, Zlib decompression, and flag assembly. """
import base64 import re import urllib.parse import zlib
defextract_flag_fragment(raw_text): """ Parses decrypted output to identify flag fragments extracted via 'xxd'. Expects 'xxd -p -l1 -s[offset]' in request and 2-char hex in response. """ global current_offset raw_text = raw_text.strip() ifnot raw_text: return
# Match Request: Extract offset from xxd command if"xxd -p -l1 -s"in raw_text: match = re.search(r"-s(\d+)", raw_text) ifmatch: current_offset = int(match.group(1))
# Match Response: If we have an offset, convert hex response to char elif current_offset != -1and re.match(r"^[0-9a-fA-F]{2}$", raw_text): try: char = bytes.fromhex(raw_text).decode("utf-8") flag_data[current_offset] = char print( f"[\033[92m+\033[0m] Fragment Found: Offset {current_offset:02} -> '{char}'" ) except Exception as e: print(f"[-] Decode error: {e}") finally: current_offset = -1
defprocess_pcap(packets, regex): """Iterates through packets, searching for encrypted payloads via regex.""" print(f"[*] Analyzing {len(packets)} packets...")
for i, p inenumerate(packets): if p.haslayer(Raw): raw_payload = p[Raw].load match = re.search(regex, raw_payload) ifmatch: decrypted = decrypt_payload(match.group(1)) print(f"[*] Packet {i + 1} matched.") # print(f"Raw: {match.group(1)[:50]}...") # Debug print(f"Decrypted: {decrypted}")
extract_flag_fragment(decrypted) print("-" * 30)
defprint_final_flag(): """Sorts fragments by offset and prints the assembled flag.""" ifnot flag_data: print("\n[-] No flag fragments found in the analyzed packets.") return
sorted_chars = [flag_data[k] for k insorted(flag_data.keys())] final_flag = "".join(sorted_chars)
defcheck_packet_by_content(packets, content): """Heuristic search for specific raw bytes in a PCAP.""" for i, p inenumerate(packets): if p.haslayer(Raw) and content in p[Raw].load: print(f"[*] Content found in Packet {i + 1}") print(p[Raw].load.decode(errors="ignore"))
# --- Main Execution ---
if __name__ == "__main__": try: # Load necessary layers load_layer("tls")
# Load PCAP pkts = rdpcap(PCAP_FILE)
# Regex to capture content between specific webshell markers payload_regex = KH + b"(.+?)" + KF