$ cat writeup.md…
$ cat writeup.md…
sunshinectf2026
Task: a Microsoft Keyboard Layout Creator (.klc) file whose DEADKEY blocks chain via an @ suffix. Solution: decode UTF-16LE, walk the dead-key chain from the grave key (0060) until it terminates at U+2600 (☀); the typed input characters spell the flag.
anon hasn't been outside in years, so he put the sun in his keyboard. find the flag he types to bring it out.
Provided file: boardwriter.klc, a Microsoft Keyboard Layout Creator (MSKLC) source file, UTF-16LE encoded. Goal: recover the flag (sun{...}) that "brings the sun out."
The .klc extension identifies a Microsoft Keyboard Layout Creator source file. These are UTF-16LE text, so the first step is a decode to UTF-8 for readable inspection.
An MSKLC file has a LAYOUT section mapping scancodes to characters, followed by any number of DEADKEY blocks. A dead key does not emit a character immediately: it waits for the next keypress and combines with it. In .klc format a dead key block looks like:
DEADKEY <deadkey_code>
<input_char_hex> <result_code>[@]
The critical detail is the trailing @:
LAYOUT entry, @ marks the produced code point as itself a dead key.DEADKEY result line, @ means the produced character is again a dead key, i.e. the chain continues.The theme is the wordplay: "put the sun in his keyboard" and "bring it out." The sun is the code point U+2600 ☀ (BLACK SUN WITH RAYS). So the intended path is a chain of dead keys that terminates by producing U+2600. Each step of the chain consumes exactly one typed character; concatenating those typed characters yields the flag ("the flag he types to bring it out").
The starting point is the LAYOUT line for the grave/backtick key, which is marked as a dead key: 0060@. From 0060 we follow the chain: each dead key has exactly one interesting input character whose result carries the @ suffix, pointing to the next dead key, until one result is 2600 with no @ (the terminator).
iconv -f UTF-16LE -t UTF-8 boardwriter.klc > boardwriter.txt
LAYOUT entry marked with @ — the grave key 0060@.DEADKEY <code> block into a map {deadkey_code: {input_char: (result_code, is_deadkey)}}.0060: at each dead key, take the single transition whose result is another dead key (@), record the typed input character, and move to the result code. Stop when the result is 2600 (☀), the terminal glyph.#!/usr/bin/env python3 # Solve "my eyes burn" — walk a .klc dead-key chain to the sun (U+2600). import re, sys # 1. Decode UTF-16LE .klc source to text. with open("boardwriter.klc", "rb") as f: text = f.read().decode("utf-16-le") # 2. Parse DEADKEY blocks into: deadkey_code -> {input_char: (result_code, is_deadkey)} deadkeys = {} current = None for line in text.splitlines(): m = re.match(r"^\s*DEADKEY\s+([0-9A-Fa-f]+)\s*$", line) if m: current = int(m.group(1), 16) deadkeys[current] = {} continue if current is not None: # "<input_hex>\t<result_hex>[@]" ; blank line ends the block t = re.match(r"^\s*([0-9A-Fa-f]+)\s+([0-9A-Fa-f]+)(@?)", line) if t: inp = chr(int(t.group(1), 16)) res = int(t.group(2), 16) deadkeys[current][inp] = (res, t.group(3) == "@") elif line.strip() == "": current = None # 3. Starting dead key = grave key marked "0060@" in the LAYOUT section. node = 0x0060 SUN = 0x2600 typed = [] # 4. Walk the chain: follow the @-marked (chained) transition each step until U+2600. while node in deadkeys: nxt = None for inp, (res, is_dead) in deadkeys[node].items(): if res == SUN: # terminal transition produces the sun typed.append(inp) nxt = None node = SUN break if is_dead: # chained dead key -> continue typed.append(inp) nxt = res if node == SUN: break if nxt is None: break node = nxt flag = "".join(typed) # Do NOT print the flag in shared writeups; verify locally only. assert node == 0x2600, "chain did not terminate at the sun" print("chain terminated at U+2600 (sun); flag length:", len(flag))
Chain trace (dead key + typed char → next dead key), ending at the sun:
0060 + 's' -> 02d0
02d0 + 'u' -> 02ed
02ed + 'n' -> 02b4
02b4 + '{' -> 02ef
02ef + <..> -> ... # continues one typed char per hop
...
02b0 + '}' -> 2600 (☀, terminal)
The concatenation of every typed input character along the walk is the flag in sun{...} form (redacted here — the recovered value is sun{REDACTED}).
Use this technique when:
.klc file (Microsoft Keyboard Layout Creator source), typically UTF-16LE encoded.DEADKEY blocks, and some result codes carry a trailing @ (chained dead keys).LAYOUT entry is marked as a dead key (e.g. 0060@ for the grave/backtick key) — that is the chain's entry point.$ cat /etc/motd
Liked this one?
Pro unlocks every complete writeup and expanded API access. $9/mo.
$ cat pricing.md$ grep --similar