> For the complete documentation index, see [llms.txt](https://jedi.gitbook.io/jedi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jedi.gitbook.io/jedi/ctf-archive/downunderctf-2025/down-to-modulate-frequencies-100-pts.md).

# 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

* [dtmf.txt](https://storage.googleapis.com/downunderctf-2025-noctf-files/noctf-files/R-KXLnu_fJGHXCSfu1Bo2?X-Amz-Algorithm=AWS4-HMAC-SHA256\&X-Amz-Credential=GOOG1ELBSKCSEHWDHBGZCFZBP3RXLJBHVAZJTTYKCMYMRJRM6O5N35G46S26H%2F20250720%2Fauto%2Fs3%2Faws4_request\&X-Amz-Date=20250720T130000Z\&X-Amz-Expires=1200\&X-Amz-SignedHeaders=host\&X-Amz-Signature=86f5f767efb628a17720ba44596df973192e163d7b828d2cc4ced526c683e521)

### 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](https://en.wikipedia.org/wiki/DTMF_signaling)

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](https://en.wikipedia.org/wiki/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

<figure><img src="/files/QvCHt67Tt4Wx2pdjCkS4" alt=""><figcaption></figcaption></figure>

We can count the sum of each row and column and convert it into the corresponding number

<table><thead><tr><th width="135"></th><th width="114" align="right">1209</th><th width="111" align="right">1336</th><th width="102" align="right">1477</th><th width="112" align="right">1633</th></tr></thead><tbody><tr><td>697</td><td align="right">1906 (1)</td><td align="right">2033 (2)</td><td align="right">2174 (3)</td><td align="right">2330</td></tr><tr><td>770</td><td align="right">1979 (4)</td><td align="right">2106 (5)</td><td align="right">2247</td><td align="right">2403</td></tr><tr><td>852</td><td align="right">2061 (7)</td><td align="right">2188 (8)</td><td align="right">2329</td><td align="right">2485</td></tr><tr><td>941</td><td align="right">2150 (*)</td><td align="right">2277 (0)</td><td align="right">2418</td><td align="right">2574</td></tr></tbody></table>

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` .&#x20;

<figure><img src="/files/HCgLNwlGOMHLNITpUFUd" alt=""><figcaption></figcaption></figure>

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 :&#x20;

```python
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

<figure><img src="/files/dQBVbd5OjdQwsWpJRttR" alt=""><figcaption></figcaption></figure>

`DUCTF{ONLYNINETIESKIDSWILLREMEMBERTHIS}`


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jedi.gitbook.io/jedi/ctf-archive/downunderctf-2025/down-to-modulate-frequencies-100-pts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
