IrisCTF 2025
by TFS
Last updated
by TFS
Last updated
File 1: main.go
(provided code for encoding).
File 2: example_input.txt
: Contains You fools! You will never get my catnip!!!!!!!
.
File 3: example_output.txt
: Contains encoded emojis for the input.
File 4: flag_output.txt
: Contains encoded emojis for the flag.
Python Scripting: Script crafted to reverse the encoding process.
Emoji Mapping: Recreated mapping between emojis and hexadecimal characters.
Key Deduction: Extracted transformation keys by comparing input and output.
Reverse the encoding process from main.go
.
Deduce the keys used for encoding.
Decode the flag from the flag_output.txt
file.
Encoding Overview
Input Transformation: Each character is transformed using random keys (char + key
).
Hex Conversion: Transformed characters are converted to hexadecimal.
Emoji Mapping: Hexadecimal values are mapped to emojis based on a predefined CharSet
.
Decoding Process
Reverse emoji mapping to hexadecimal using a custom function.
Convert the hexadecimal string to the intermediate transformed text.
Deduce the keys by comparing the transformed text with example_input.txt
.
Reverse the key transformation to recover the original flag text.
Python Script
import json
from collections import defaultdict
# Define CharSet mapping for decoding
CharSet = {
"🐱": "0", "🐈": "1", "😸": "2", "😹": "3",
"😺": "4", "😻": "5", "😼": "6", "😽": "7",
"😾": "8", "😿": "9", "🙀": "A", "🐱👤": "B",
"🐱🏍": "C", "🐱💻": "D", "🐱👓": "E", "🐱🚀": "F"
}
# Reverse CharSet for decoding emojis back to hex
# Reverse CharSet for decoding emojis back to hex
def reverse_charset(emojis):
result = ""
buffer = ""
max_emoji_length = max(len(k) for k in CharSet) # Determine longest emoji
i = 0
while i < len(emojis):
buffer = ""
# Try to match from current position with longest possible emoji
for j in range(max_emoji_length, 0, -1):
if i + j <= len(emojis):
buffer = emojis[i:i + j]
if buffer in CharSet:
result += CharSet[buffer]
i += j - 1 # Move index forward by matched length
break
else:
raise ValueError(f"Unrecognized emoji sequence: {buffer}")
i += 1 # Move to next character after match
return result
def debug_emojis(emojis):
print("Debugging Emojis:")
for idx, char in enumerate(emojis):
print(f"Index {idx}: {char} (Code: {ord(char)})")
# Deduce keys from example input and output
def deduce_keys(example_input, example_output):
# Decode emojis to hex and then to the intermediate text
hex_decoded = reverse_charset(example_output)
intermediate_text = bytes.fromhex(hex_decoded).decode()
# Calculate keys
keys = [ord(intermediate_text[i]) - ord(example_input[i]) for i in range(len(example_input))]
return keys
# Decode flag output
def decode_flag(flag_output, keys):
# Decode emojis to hex and then to the intermediate text
hex_decoded = reverse_charset(flag_output)
intermediate_text = bytes.fromhex(hex_decoded).decode()
# Reconstruct original text by reversing the key transformation
original_text = "".join(chr(ord(intermediate_text[i]) - keys[i]) for i in range(len(intermediate_text)))
return original_text
# Load input and outputs
with open("example_input.txt", "r", encoding="utf-8") as f:
example_input = f.read().strip()
with open("example_output.txt", "r", encoding="utf-8") as f:
example_output = f.read().strip()
with open("flag_output.txt", "r", encoding="utf-8") as f:
flag_output = f.read().strip()
# Deduce keys and decode the flag
keys = deduce_keys(example_input, example_output)
flag = decode_flag(flag_output, keys)
print("Decoded Flag:", flag)
Execution Steps
Place all provided files in the script directory.
Run the script:
python decodekitty.py
Output will display the decoded flag.
irisctf{s0m371m3s_bY735_4r3n7_wh47_y0u_3xp3c7}
The encoding process was reversed by deducing transformation keys from example input-output pairs and reconstructing the original text. This allowed successful decoding of the flag.
Key Deduction: Known input-output pairs simplify reverse engineering.
Dynamic Mappings: Handling custom mappings like emojis requires attention to detail.
Tags: ctf
, emoji encoding
, reverse engineering
, golang
, python
.
File: klogger.pcapng
(USB capture with over 9000 rows).
Wireshark/TShark: To analyze USB protocol data in the .pcapng
file.
Usb_Keyboard_Parser.py: A Python script from 5h4rrk's repository to parse USB keyboard HID data.
Identify the type of USB data in the .pcapng
file.
Decode the HID data captured in the USB packets.
Extract the hidden flag from the keystrokes.
Thought Process
Observing the file name (klogger.pcapng
) and the USB
protocol in the capture hints at a USB keyboard data challenge.
USB keyboards communicate keystrokes via HID (Human Interface Device) data in USB packets.
Decoding the keystrokes will reveal the typed text, potentially containing the flag.
Steps Taken
Analyzed the PCAP File:
Opened klogger.pcapng
in Wireshark.
Observed URB_INTERRUPT
packets, which typically contain HID data for USB keyboards.
Used Usb_Keyboard_Parser.py:
Downloaded the script from 5h4rrk/CTF-Usb_Keyboard_Parser.
This script decodes USB HID data into readable keystrokes using predefined mappings of USB HID codes to characters.
Executed the Parser:
python Usb_Keyboard_Parser.py klogger.pcapng
Output:
[-] Found Modifier in 310 packets [-]
[+] Using filter "usb.capdata" Retrieved HID Data is :
Hheey AAalicce! Ii tthink Ii''m ssupppooseed too giivee yoou tiss fllaag:
iriisctfF{[tthis_akeyloggeer_iisS_too_hard_to_use}
Understanding the Output
The parser successfully decoded the USB HID data.
Some keystrokes appeared doubled due to repeat packets (Hheey
, AAalicce
, etc.), but the text was clear enough to identify the flag.
irisctf{this_keylogger_is_too_hard_to_use}
The challenge involved analyzing USB keyboard data captured in a .pcapng
file. Using the Usb_Keyboard_Parser.py
script, the HID data was decoded into readable keystrokes, revealing the flag.
USB HID Data: USB keyboards send data as HID packets, which can be parsed to reconstruct keystrokes.
Wireshark/TShark Integration: Tools like Wireshark and TShark are invaluable for analyzing USB traffic.
Scripting Tools: Custom parsers like Usb_Keyboard_Parser.py
simplify the process of decoding complex USB captures.
Tags: usb
, keylogger
, HID
, ctf
, packet analysis
, python
.
File: logs.json
(500,000 rows of network logs).
Python Scripting: To analyze and filter network activity.
Pattern Matching: Regular expressions to identify suspicious domains and user activities.
Command-Line Utilities: strings
and grep
for targeted searches in large datasets.
Identify any suspicious or illegitimate network activity.
Trace the activity back to the responsible user.
Extract the username for the flag.
Thought Process
The description mentions illegal activity on the network, so the task likely involves finding suspicious domains or unauthorized access.
Since the file is a JSON log with 500,000 rows, using scripts and targeted searches would be the most efficient approach.
The flag format irisctf{username}
suggests we need to identify the user associated with the illegitimate activity.
Steps Taken
Initial Analysis with Python:
Analyzed the logs to extract all domains accessed, excluding internal company domains (*.insurance.corp
).
Wrote the following Python script:
import collections
import re
def analyze_logs(file_path):
domains = collections.Counter()
with open(file_path, 'r') as f:
for line in f:
# Extract Domains
domain_match = re.search(r'\b([a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})\b', line)
if domain_match:
domain = domain_match.group(1)
# Exclude domains ending with 'insurance.corp'
if not domain.endswith('insurance.corp'):
domains[domain] += 1
print("\nLeast 10 Domains (Excluding 'insurance.corp'):")
for domain, count in domains.most_common()[-10:]:
print(f"{domain}: {count}")
# Example Usage
log_file = 'logs.json' # Replace with your actual log file
analyze_logs(log_file)
Output:
Least 10 Domains (Excluding 'insurance.corp'):
g.co: 12
deloitte.com: 12
justgiving.com: 12
slate.com: 8
as.com: 8
breachforums.st: 4
bmj.com: 4
welt.de: 4
copious-amounts-of-illicit-substances-marketplace.com: 2
smith-wesson.com: 2
Identified Suspicious Domain:
The domain breachforums.st
stood out as potentially illegal.
Used strings
and grep
to locate all log entries related to this domain:
strings logs.json | grep breach
Output:
{"host": "primary", "source": "stream:dns", "sourcetype": "stream:dns", "_time": "2024-12-04 06:33:36.80", "data": {"timestamp": "2024-12-04 06:33:36.803488", "protocol_stack": "ip:udp:dns", "transport": "udp", "src_ip": "10.33.18.209", "src_port": 52836, "dest_ip": "10.33.0.2", "dest_port": 53, "transaction_id": 50295, "queries": [{"type": "A", "class": "IN", "name": "breachforums.st"}]}}
{"host": "primary", "source": "stream:dns", "sourcetype": "stream:dns", "_time": "2024-12-04 06:33:37.18", "data": {"timestamp": "2024-12-04 06:33:37.175597", "protocol_stack": "ip:udp:dns", "transport": "udp", "src_ip": "10.33.0.2", "src_port": 53, "dest_ip": "10.33.18.209", "dest_port": 52836, "transaction_id": 50295, "answers": [{"type": "A", "class": "IN", "name": "breachforums.st", "addr": "185.129.102.136"}]}}
Source IP associated with the queries: 10.33.18.209
.
Traced IP to a User:
Searched for logs containing the IP 10.33.18.209
and uid
(user identifier):
strings logs.json | grep 10.33.18.209 | grep uid
Output:
{"host": "primary", "source": "udp:514", "sourcetype": "syslog", "_time": "2024-12-04 04:58:36.95", "data": {"_raw": "2024-12-04 04:58:35.622504||https://sso.evil-insurance.corp/idp/profile/SAML2/Redirect/SSO|/idp/profile/SAML2/Redirect/SSO|5b52053ac1ab1f4935a3d7d6c6aa4ff0|authn/MFA|10.33.18.209|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3 Edge/16.16299|https://sso.evil-insurance.corp/ns/profiles/saml2/sso/browser|llloyd||uid|service.evil-insurance.corp|https://sso.evil-insurance.corp/idp/sso|url:oasis:names:tc:SAML:2.0:protocol|urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect|urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST|kzYQV+Jk2w3KkwmRjR+HK4QWVQ3qzLPLgA5klV2b8bQT+NLYLeqCZw5xUGKbx1U1158jlnUYRrILtVTtMkMdbA==|urn:oasis:names:tc:SAML:2.0:nameid-format:transient|_60b0fd4b0ed5bba3474faeb85b3944e|2024-12-04 04:58:35.622504|_c4b56d58-625b-49aa-b859-4a2068422979||||urn:oasis:names:tc:SAML:2.0:status:Success|||false|false|true"}}
Username associated with the IP: llloyd
.
irisctf{llloyd}
By analyzing the logs, we identified breachforums.st
as a suspicious domain and traced the activity to IP 10.33.18.209
. Further searches revealed that the user responsible was llloyd
, allowing us to complete the challenge.
Log Analysis: Large datasets can be navigated efficiently using tools like Python and grep
.
Suspicious Patterns: Focusing on anomalies (e.g., suspicious domains) helps narrow down the search.
Attribution: Tracing activity to users or devices is critical in forensic investigations.
Tags: log analysis
, forensics
, ctf
, json
, python scripting
.
File: dotdotdot.iq
Inspectrum: A tool for analyzing IQ (in-phase and quadrature) files. (Inspectrum)
Morse Code Decoding: Manual transcription and decoding of visible Morse code.
Open the .iq
file and analyze its contents.
Identify any patterns or messages within the file.
Decode the extracted Morse code to obtain the flag.
Thought Process
.iq
files are commonly associated with signals that can be analyzed visually for patterns using tools like Inspectrum.
The description implies Morse code is embedded within the file, which needs to be extracted and decoded.
Steps Taken
Opened the File in Inspectrum:
Loaded dotdotdot.iq
into Inspectrum.
Initially, no visible patterns were found.
Adjusted Power Levels:
Adjusted the power max and power min settings in Inspectrum.
This revealed a clear line of Morse code in the spectrogram.'
Manually Transcribed Morse Code:
Carefully transcribed the Morse code line from the spectrogram.
Resulting Morse code:
.. .-. .. ... -.-. - ..-. -. ----- .---- ... ...--
--. ----- -
-. ----- - .... .---- -. --.
----- -.
-- -.-- -- ----- .-. ... .
Decoded Morse Code:
Translated the Morse code manually using a Morse code chart:
Morse Code:
.. .-. .. ... -.-. - ..-. -. ----- .---- ... ...--
--. ----- -
-. ----- - .... .---- -. --.
----- -.
-- -.-- -- ----- .-. ... .
Plaintext:
IRISCTFN01S3
G0T
N0TH1NG
0N
MYM0RSE
Constructed the Flag:
Combined the plaintext lines to form the flag.
Final Flag: irisctf{n01s3_g0t_n0th1ng_0n_my_m0rse}
irisctf{n01s3_g0t_n0th1ng_0n_my_m0rse}
By analyzing the .iq
file in Inspectrum, adjusting the power levels, and manually transcribing and decoding the visible Morse code, the challenge was successfully solved, and the flag was retrieved.
Signal Visualization: Tools like Inspectrum are essential for analyzing IQ files and identifying hidden patterns.
Morse Code Decoding: Manually decoding Morse can be tedious but effective when automated solutions are unavailable.
Tags: iq files
, morse code
, ctf
, signal analysis
, manual decoding
.