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
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 |
![]() |
---|
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
- 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)