Skip to main content
  1. My Blog Posts and Stories/

GreyCTF 2023 Finals: Musical Talent

·423 words·2 mins

This is the author’s writeup for the challenges Musical Talent in the misc category.

This describes the intended solution when I made the challenge.

Challenge description #

Can you appreciate the hidden message in my song? This is only for the musically & mathematically talented.

  • Junhua

A file called result.mid was provided

My Notes #

The file #

The file is an old .mid file. This is a standard that describes a communication protocol for music. It consists of a set of instructions for pitch and tempo that uses less space than an equivalent audio recording.

Visualization
Visualized file

After opening the recoding, we see that it consists of multiple notes, each playing for a fixed length of time. There are also no notes played together at the same time.

Let us read this into a program to be processed further.

We can make use of mingus which supports different Midi file operations using python.

We can make use of mingus.midi.midi_file_in.MIDI_to_Composition which converts the midi file into mingus container objects.

After reading the midi file, we can extract the notes into a frequency table before we process them. Once we sort them, we can map the most common notes to the most common letters in the english language and slowly adjust them from there.

The solution script is shown below.

import os
from typing import List, Tuple
from mingus.containers import NoteContainer, Track
from mingus.midi.midi_file_in import MIDI_to_Composition

path = os.path.join(os.path.dirname(__file__), "dist", "result.mid")

# Parsing with mingus
readResult :Tuple[List[Track], int] = MIDI_to_Composition(path)
results, _ = readResult

# results now contain the notes, compute the frequencies of the notes and the ordering
freq = {}
acc = []

for track in results:
    noteContainer : NoteContainer
    for _, _, noteContainer in track.get_notes():
        for note in noteContainer:
            note_name = f"{note.name}{note.octave}"
            freq[note_name] = 1 if note_name not in freq else freq[note_name] + 1
            acc.append(note_name)

# Sort the frequencies
freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)

# Map each of them to a letter and use frequency analysis to solve it.
letters = " etaiosnrlcdhfmupygbw,.vkxz'q0j164725_839-\\\{}"

# Map the frequencies to letters (Most common should be space)
mapping = {}
for i, (note, _) in enumerate(freq):
    mapping[note] = letters[i]

# Map the notes to letters
final_passage = []
for note in acc:
    final_passage.append(mapping[note])

passage = ''.join(final_passage)
with open('test.txt', 'w') as f:
    f.write(passage)
  1. Source Music File
  2. Online MIDI file reader
  3. Intended Solution writeup by NeoBeo