DownUnderCTF 2025 — Down To Modulate Frequencies! (100 pts)
Description
Dear CSI,
One of the scavengers found an abandonded station still transmitting. Its been so long, no one remembers how to decode this old tech, can you figure out what was being transmitted?
Decode the alphanumeric message and wrap it in DUCTF{}.
Regards,
pix
Attachments
Solution
We were given a txt file with the name of dtmf. If we search in google, we find out that DTMF refer to Dual-tone multi-frequency
Inside the txt file, we see that there is a long string number with the length of 428 number
jedi@aqua: /mnt/d/CTF/ductf/beginner
$ cat dtmf.txt [20:10:24]
22472247224724182247224724182106210621062418232923292329241822472247241819791979197924182247224724182174217424182188241819791979197924182174217424182061206120612061241821062106241819791979197924182174241820612061206120612418232924181979197919792418210621062106241821062106210624182061206120612418217421742418224724182174217424182247241820332033241821742174241820612061206124182188241819791979241819791979197924182061206120612061%
jedi@aqua: /mnt/d/CTF/ductf/beginner
$ python3 [20:10:26]
Python 3.12.3 (main, Jun 18 2025, 17:59:45) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> len('22472247224724182247224724182106210621062418232923292329241822472247241819791979197924182247224724182174217424182188241819791979197924182174217424182061206120612061241821062106241819791979197924182174241820612061206120612418232924181979197919792418210621062106241821062106210624182061206120612418217421742418224724182174217424182247241820332033241821742174241820612061206124182188241819791979241819791979197924182061206120612061')
428
If we check the wikipedia that explain more about DTMF, we see this table. The DTMF telephone keypad is laid out as a matrix of push buttons in which each row represents the low frequency component and each column represents the high frequency
We can count the sum of each row and column and convert it into the corresponding number
12091336147716336971906 (1)2033 (2)2174 (3)23307701979 (4)2106 (5)224724038522061 (7)2188 (8)232924859412150 (*)2277 (0)24182574
After we convert all of the number (split into 4 number, convert it based on the table), we see the format is like this : 666#66#555#999…
We suspect that this is correlate with multi-tap text entry. If we convert 666#66#555#999, we get ONLY .
So, we can make a solver to convert the first string that convert the long string into DTMF table, and then convert result to multi-tap text entry.
The solver that i use is like this :
def solver():
data = "22472247224724182247224724182106210621062418232923292329241822472247241819791979197924182247224724182174217424182188241819791979197924182174217424182061206120612061241821062106241819791979197924182174241820612061206120612418232924181979197919792418210621062106241821062106210624182061206120612418217421742418224724182174217424182247241820332033241821742174241820612061206124182188241819791979241819791979197924182061206120612061"
# 1. Mapping from frequency sum to keypad digit
freq_sum_to_digit = {
'1979': '4', '2033': '2', '2061': '7', '2106': '5',
'2174': '3', '2188': '8', '2247': '6', '2329': '9',
'2418': '#' # The '#' key is our separator
}
# 2. Mapping for multi-tap text entry
multitap_map = {
'2': 'ABC', '3': 'DEF', '4': 'GHI',
'5': 'JKL', '6': 'MNO', '7': 'PQRS',
'8': 'TUV', '9': 'WXYZ'
}
# Split the data string into 4-digit chunks, convert the chunks into a sequence of digits, and split the sequence by the '#' separator
chunks = [data[i:i+4] for i in range(0, len(data), 4)]
digit_sequence = "".join([freq_sum_to_digit.get(chunk, "?") for chunk in chunks])
letter_sequences = digit_sequence.split('#')
# 3. Decode the multi-tap sequences to get the flag
message = ""
for seq in letter_sequences:
if seq:
digit = seq[0]
press_count = len(seq)
if digit in multitap_map:
char_set = multitap_map[digit]
char_index = (press_count - 1) % len(char_set)
message += char_set[char_index]
flag = f"DUCTF{{{message}}}"
return flag
if __name__ == "__main__":
final_flag = solver()
print(f"Decoded flag: {final_flag}")
Flag
DUCTF{ONLYNINETIESKIDSWILLREMEMBERTHIS}