Hubert Hackin''
  • All posts
  • About
  • Our CTF

NSEC25 Sailorkidz-activity-book - Thu, May 22, 2025 - Marx314, Valesca

Kindergarden challenge | Craptography | Nsec25

Sailorkidz-activity-book

Challenge Recap

We received an image and an audio file and a cryptic hint:

They have all kind of activities for kids aboard to keep them busy while parents get wasted or spend all their cash.
I’m sure that you can crush the puzzles from the SailorKidz activity magazine they give at the Craptography daycamp.

The image


Sailormoon kidz

Lets lookup for all the diacritical from official source…

From wikipedia: https://en.wikipedia.org/wiki/Combining_Diacritical_Marks

I first tried to use the official diacritical value… it was a waste of time parsing this, scratch that!

It’s about the journey not the destination


Lets restart, be creative with the name (buckle-up, french canadian naming things ahead!), top if not specified, below if specified

The message seem to start with “Ahoy” and end with “Flag” from that we infer some mappings.

ABCDEFGHIJKLMNOPQRSTUVWXYZ
A 
F
+5  ==  ̆ below == l
+11 ==  ̆ == f
+6  ==  ̋ == g
+7  == ~ below == h
+14 == o == o
+24 == é below == y

Guessing the second word, 15 letter words with A at position 6 and 10, there is not a lot of them this kind of tooling: https://wordswithletters.org/find-words-with-letters-in-certain-positions will do the trick!

160 words to look at but lots of them have A at other place about 27 that pycharm seems to “approve”

words = """anticapitalisms
anticapitalists
antiradicalisms
automatisations
automatizations
axiomatisations
axiomatizations
..."""

word_left = [w for w in words.splitlines() if w.count("a") == 2]
print(word_left)  

the 5th valid word seem appropriate: congratulations

let’s continue with what we have

congratulations

we can fill our conversion table and test it against the flag!

cipher_flag = ['u-below', 'u', '', 'double-é', 'hyphen',
               'cedile-below-inverted', 'o', '~-below', '', 'trema',
               'u-below', 'é-below', 'o', 'x', 'u', '', '~', '~',
               'é-below', 'n-below', '-below']

conversion_table = {'u-below': 'f',
                    'u': 'l',
                    'double-é': 'g',
                    '~-below': 'h',
                    'cedile-below-inverted': 'c',
                    'o': 'o',
                    'cinconflex': 'n',
                    'n': 'r',
                    '-': 't',
                    'hyphen': '-',
                    'trema': 'u',
                    'question': 'i',
                    '~': 's',
                    'é-below': 'y',
                    '': 'a'}


def decode_flag():
    print("".join([conversion_table.get(c, '?') for c in cipher_flag]))


decode_flag()

we are close but still: Flag-cohaufyoxlassy??

trying the whole thing and guessing words by word

Ahoy! Congratulations on
solvin’ ?is

this look like shipmate language for “dis”

conversion_table['à'] = 'v'
conversion_table['-below'] = 'd'  # only one character not known, n-below

Ahoy! Congratulations on
solvin’ dis difficult ?u??l?.
Li?? all good saildor?id?,
y? n??ds a r??ard. If y?
?ants t’ hoist a flag h?r?
?? on?:

I’m assuming:

  • “difficult puzzle”
  • “a reward” but could be “a retard” ¯\_(ツ)_/¯
  • “hoist a flag here”
conversion_table['é'] = 'e'
Ahoy! Congratulations on
solvin’ dis difficult puzzle.
Like all good saildorkidz
ye needs a reward. If ye
wants t’ hoist a flag here
?e one: Flag-cohaufyoxlass
ypd
Sailormoon kidz
conversion_table['n-below'] = 'p'
conversion_table['/'] = 'z'
conversion_table['.-below'] = 'k'
conversion_table['à-double'] = 't'
decode_flag()  # the message isn't perfect, but we have the flag!

DO NOT FORGET THE LAST 3 CHARACTERS

flag-cohaufyoxlassypd

Just the code

cipher_flag = ['u-below', 'u', '', 'double-é', 'hyphen',
               'cedile-below-inverted', 'o', '~-below', '', 'trema',
               'u-below', 'é-below', 'o', 'x', 'u', '', '~', '~',
               'é-below', 'n-below', '-below']

conversion_table = {'u-below': 'f', 'u': 'l', 'double-é': 'g', 
                    '~-below': 'h', 'cedile-below-inverted': 'c', 
                    'o': 'o', 'cinconflex': 'n', 'n': 'r', '-': 't',
                    'hyphen': '-', 'trema': 'u', 'question': 'i', '~': 's', 
                    'é-under': 'y', '': 'a', 'à': 'v', '-under': 'd', 'é': 'e',
                    'n-under': 'p', '/': 'z', '.-under': 'k', 'à-double': 'w'}


def decode_flag():
    print("".join([conversion_table.get(c, '?') for c in cipher_flag]))


decode_flag()

The audio file


Step 1 – Inspecting the Audio

Audacity in Spectrogram view

  • 17 minutes of beep, beep-beep-beep, beep-beep-beep, beep-beep-beep-beep, beep-beep-beep, beep-beep, beep-beep…
  • Opened the file in Audacity
  • Changed to spectrogram view to see the pulse
  • Transcribed the pulses into numbers (values from 1 to 5) manually:
numbers = [
    1, 3, 3, 4, 3, 3, 2, 2, 4, 2, 1, 1, 4, 4, 4, 3, 5, 4, 3, 4, 4, 5, 2, 3, 1, 1, 5, 1, 1, 5, 3, 1, 1, 5, 1, 1, 4, 2, 3, 3,
    1, 5, 1, 4, 4, 4, 2, 3, 1, 5, 1, 3, 3, 4, 1, 4, 1, 5, 2, 1, 3, 4, 4, 2, 4, 4, 2, 3, 1, 5, 1, 3, 2, 4, 1, 4, 4, 3, 1,
    1, 2, 4, 3, 1, 3, 4, 4, 2, 4, 3, 3, 5, 4, 2, 3, 4, 2, 2, 4, 2, 1, 1, 3, 2, 3, 5, 1, 1, 4, 2, 4, 4, 4, 4, 5, 2, 3, 4,
    4, 4, 2, 3, 1, 5, 2, 1, 3, 1, 1, 1, 2, 2, 2, 4, 4, 3, 2, 1, 3, 1, 1, 1, 2, 2, 2, 3, 5, 4, 3, 5, 1, 5, 3, 3, 4, 4, 5,
    2, 3, 4, 4, 4, 5, 2, 3, 4, 2, 1, 2, 4, 5, 1, 1, 5, 1, 4, 2, 1, 3, 4, 4, 5, 4, 2, 2, 1, 3, 4, 4, 5, 4, 2, 2, 1, 2, 4,
    5, 1, 1, 5, 3, 4, 3, 3, 1, 5, 4, 3, 1, 5, 5, 1, 1, 5, 3, 3, 1, 4, 1, 2, 2, 1, 1, 3
]

Step 2 – Decoding the Numbers

The challenge description mentioned “SailorKidz activity magazine” and the numbers were between 1 and 5, so I guessed an old/child-ish cipher after few search I found Polybius Square / Tap Code. (the I and J share the same tile)

Here’s what a Polybius square look:

  1 2 3 4 5
1 A B C D E
2 F G H I K
3 L M N O P
4 Q R S T U
5 V W X Y Z

Decoding code:

polybius_square = [
    ['A', 'B', 'C', 'D', 'E'],
    ['F', 'G', 'H', 'I', 'K'],
    ['L', 'M', 'N', 'O', 'P'],
    ['Q', 'R', 'S', 'T', 'U'],
    ['V', 'W', 'X', 'Y', 'Z']
]

pairs = [(numbers[i], numbers[i + 1]) for i in range(0, len(numbers), 2)]
decoded = ''
for row, col in pairs:
    decoded += polybius_square[row - 1][col - 1]

print(decoded)

Decoded message:

CONGRATSYOUHAVELEARNEDTHECODEFORTHECIDSAILORSPROGRAMPARTTWOTHEFLAGISFLAGHYPENTWOTWOFIVEDFOURFOURFIVEONESEVENDBFC

Step 3 – Flagging properly is an acquired skill

In the excitement of the moment I submitted what was in front of me without any further thinking and got a wrong flag 😕

Then I tried to read it and saw:

FLAGISFLAGHYPENTWOTWOFIVEDFOURFOURFIVEONESEVENDBFC

I thought, ah!

FLAG-TWOTWOFIVEDFOURFOURFIVEONESEVENDBFC

Wrong again 🙁

I then proceeded to convert the numbers but ignore the rest:

FLAG-2254517

Still not 😦

Maybe I should keep the letters at the end:

FLAG-2254517DBFC

Nope, wrong 😨

My teammate told me to ask for !help, a wild Laurent D appeared before an average CTF enjoyer, it’s super effective!

After a polite exchange, he told me to read properly…

I then realized that I had omitted the D from that sequence:

FLAG-TWOTWOFIVEDFOURFOURFIVEONESEVENDBFC
---------------*------------------------
FLAG-225D4517DBFC

I immediately left to grab a beer but while I was away Laurent went to our table to congratulate us, we were the first blood!

Just the code

numbers = [
    1, 3, 3, 4, 3, 3, 2, 2, 4, 2, 1, 1, 4, 4, 4, 3, 5, 4, 3, 4, 4, 5, 2, 3, 1, 1, 5, 1, 1, 5, 3, 1, 1, 5, 1, 1, 4, 2, 3, 3,
    1, 5, 1, 4, 4, 4, 2, 3, 1, 5, 1, 3, 3, 4, 1, 4, 1, 5, 2, 1, 3, 4, 4, 2, 4, 4, 2, 3, 1, 5, 1, 3, 2, 4, 1, 4, 4, 3, 1,
    1, 2, 4, 3, 1, 3, 4, 4, 2, 4, 3, 3, 5, 4, 2, 3, 4, 2, 2, 4, 2, 1, 1, 3, 2, 3, 5, 1, 1, 4, 2, 4, 4, 4, 4, 5, 2, 3, 4,
    4, 4, 2, 3, 1, 5, 2, 1, 3, 1, 1, 1, 2, 2, 2, 4, 4, 3, 2, 1, 3, 1, 1, 1, 2, 2, 2, 3, 5, 4, 3, 5, 1, 5, 3, 3, 4, 4, 5,
    2, 3, 4, 4, 4, 5, 2, 3, 4, 2, 1, 2, 4, 5, 1, 1, 5, 1, 4, 2, 1, 3, 4, 4, 5, 4, 2, 2, 1, 3, 4, 4, 5, 4, 2, 2, 1, 2, 4,
    5, 1, 1, 5, 3, 4, 3, 3, 1, 5, 4, 3, 1, 5, 5, 1, 1, 5, 3, 3, 1, 4, 1, 2, 2, 1, 1, 3
]

polybius_square = [
    ['A', 'B', 'C', 'D', 'E'],
    ['F', 'G', 'H', 'I', 'K'],
    ['L', 'M', 'N', 'O', 'P'],
    ['Q', 'R', 'S', 'T', 'U'],
    ['V', 'W', 'X', 'Y', 'Z']
]

pairs = [(numbers[i], numbers[i + 1]) for i in range(0, len(numbers), 2)]
decoded = ''
for row, col in pairs:
    decoded += polybius_square[row - 1][col - 1]

print(decoded)

Back to Home


Hackez la Rue! | © Hubert Hackin'' | 2025-05-26 | theme hugo.386