back to blog

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}