Category: Misc

scriptCTF is a 48-hour jeopardy style CTF for hackers to test their skills against creative and innovative CTF challenges. We have mostly beginner friendly challenges, with a few hard ones. scriptCTF makes CTFs fun and approachable for all skill levels! This is hosted by ScriptSorcerers and some members of n00bzUnit3d (as a replacement of n00bzCTF).
When we opened the out.txt
file given in the challenge, we found something quite meaningless.
ðŸ³ðŸ£ðŸ²ðŸ©ðŸ°ðŸ´ðŸƒðŸ”ðŸ†ðŸ»ðŸ€³ðŸðŸ€°ðŸªðŸ€±ðŸŸðŸ€³ðŸ®ðŸ£ðŸ€°ðŸ¤ðŸ€±ðŸ®ðŸ§ðŸŸðŸ€±ðŸ³ðŸŸðŸ·ðŸ€³ðŸ€±ðŸ²ðŸ¤ðŸŸðŸ€´ðŸ®ðŸ¤ðŸŸðŸ¦ðŸµðŸ®ðŸ€¡ðŸ€±ðŸ¥ðŸ€´ðŸ€¶ðŸ¤ðŸ½
I decided to Save Page As. So, the dowloaded file was a bit of short but looked similar. In other words, it’s an image created by “incorrect decoding of UTF-8 emoji bytes“. For example; “🳔 actually corresponds to a Mahjong tile/emoji like “🁳”. This means out.txt
was opened with the wrong encoding.
Solution Hypothesis
These Mahjong tiles actually have different Unicode codepoints, but they all appear in a consecutive block (U+1F000 – U+1F02F). So, each tile is a number. We need to convert these back to ASCII.
Steps:
- Get the Unicode code of the characters in the file.
- Subtract the Mahjong base (
0x1F000
), and the remainder is a number. - Try converting these numbers into a binary or ASCII map.
Conclusion
This code wasvals
→ Converts Mahjong tiles to numbers.
Three different methods are being tried:
- Direct
chr()
→ maybe there’s already an ASCII equivalent.. - Hex string → maybe flag hex encoded
- Binary parity → 0/1 map → ASCII.
def decode_tiles(text):
codes = [ord(ch) for ch in text if ch.strip()]
base = 0x1F000
values = [c - base for c in codes]
return values
with open("out.txt", "r", encoding="utf-8") as f:
data = f.read().strip()
vals = decode_tiles(data)
print("[+] Unicode offsets:", vals)
try:
ascii_str = "".join(chr(v) for v in vals)
print("[ASCII] ", ascii_str)
except:
pass
hex_str = "".join(f"{v:02x}" for v in vals)
print("[HEX] ", hex_str)
try:
print("[HEX->ASCII]", bytes.fromhex(hex_str).decode())
except:
pass
bin_str = "".join("1" if v % 2 else "0" for v in vals)
print("[BINARY] ", bin_str)
try:
out = int(bin_str, 2).to_bytes((len(bin_str)+7)//8, 'big')
print("[BINARY->ASCII]", out)
except:
pass
[+] Unicode offsets: [115, 99, 114, 105, 112, 116, 67, 84, 70, 123, 51, 109, 48, 106, 49, 95, 51, 110, 99, 48, 100, 49, 110, 103, 95, 49, 115, 95, 119, 51, 49, 114, 100, 95, 52, 110, 100, 95, 102, 117, 110, 33, 49, 101, 52, 54, 100, 125]
[ASCII] scriptCTF{3m0j1_3nc0d1ng_1s_w31rd_4nd_fun!1e46d}
[HEX] 7363726970744354467b336d306a315f336e633064316e675f31735f77333172645f346e645f66756e2131653436647d
[HEX->ASCII] scriptCTF{3m0j1_3nc0d1ng_1s_w31rd_4nd_fun!1e46d}
[BINARY] 110100100111001110100101111111100100010101110001
[BINARY->ASCII] b'\xd2s\xa5\xfeEq'
FLAG: scriptCTF{3m0j1_3nc0d1ng_1s_w31rd_4nd_fun!1e46d}