
IrisCTF 2025
by TFS


Challenge Category
Cryptography
KittyCrypt - Emoji Mapping
Solution
Files/Links Provided
File 1:
main.go
(provided code for encoding).File 2:
example_input.txt
: ContainsYou 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.
Tools/Methods Used
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.
Goals
Reverse the encoding process from
main.go
.Deduce the keys used for encoding.
Decode the flag from the
flag_output.txt
file.
Solution
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.
Final Answer
irisctf{s0m371m3s_bY735_4r3n7_wh47_y0u_3xp3c7}
Summary
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.
Remarks/Tags/Lessons Learned
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
.
Forensics
deldeldel - USB PCAP Analysis from Keyboard Device
Solution
Files/Links Provided
File:
klogger.pcapng
(USB capture with over 9000 rows).
Tools/Methods Used
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.
Goals
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.
Solution
Thought Process
Observing the file name (
klogger.pcapng
) and theUSB
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.
Final Answer
irisctf{this_keylogger_is_too_hard_to_use}
Summary
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.
Remarks/Tags/Lessons Learned
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
.
Tracerm 1 - Large Logs Pattern Analysis
Solution
Files/Links Provided
File:
logs.json
(500,000 rows of network logs).
Tools/Methods Used
Python Scripting: To analyze and filter network activity.
Pattern Matching: Regular expressions to identify suspicious domains and user activities.
Command-Line Utilities:
strings
andgrep
for targeted searches in large datasets.
Goals
Identify any suspicious or illegitimate network activity.
Trace the activity back to the responsible user.
Extract the username for the flag.
Solution
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
andgrep
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
anduid
(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
.
Final Answer
irisctf{llloyd}
Summary
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.
Remarks/Tags/Lessons Learned
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
.
OSINT
Checking Out of Winter -
Sleuths and Sweets -
Not Eelaborate -
Late Night Bite -
fuel deal -
Radio Frequency
dotdotdot - Audio Signal (.iq) Analysis with Morse Code
Solution
Files/Links Provided
File:
dotdotdot.iq
Tools/Methods Used
Inspectrum: A tool for analyzing IQ (in-phase and quadrature) files. (Inspectrum)
Morse Code Decoding: Manual transcription and decoding of visible Morse code.
Goals
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.
Solution
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}
Final Answer
irisctf{n01s3_g0t_n0th1ng_0n_my_m0rse}
Summary
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.
Remarks/Tags/Lessons Learned
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
.
Last updated