Hacktheon Sejong 2026 Quals Writeup CTF/Wargame

Hacktheon Sejong 2026 Quals Until Executing Writeup

Hacktheon Sejong 2026 Quals Until Executing 문제 풀이Hacktheon Sejong 2026 Quals Until Executing writeup

Contents

Summary

stripped OCaml native 바이너리지만 동적 심볼에 camlMain, camlProc_a_engine, camlProc_b_engine이 남아 있었다. 실제 verifier는 parent가 아니라 fork() 이후 child process에서 돈다.

Analysis

입력 조건은 길이 64와 고정 alphabet이다.

text
length   = 64
alphabet = abcdefghijklmnopqrstuvwxyz_0123456789!

OCaml immediate integer는 (n << 1) | 1 형태다. disassembly에서 길이 비교값으로 쓰인 0x81은 64를 뜻한다.

Proc_a_engine과 Proc_b_engine은 모두 explode -> run -> collapse 구조였다. run에서 check closure를 쌓고 마지막 collapse에서 검증을 실행한다. 제목의 Until Executing은 이 구조를 가리킨다.

각 문자는 ASCII 값 대신 alphabet index를 tagged value로 바꿔 쓴다.

text
a -> 1
b -> 3
c -> 5
...

Proc_b의 current check와 state update를 Python으로 옮겨 candidate를 줄였다. branch가 빠르게 줄어들어 끝에는 하나만 남았고 그 candidate를 Proc_a checker에도 넣어 다시 확인했다.

복구된 내부 문자열은 아래와 같다.

text
ovajumher0erwkl28_i8eecp!hb5enitsj6ly5hx05qel7a2z1gb6y8vi4fd4l93

Flag

hacktheon2026{ovajumher0erwkl28_i8eecp!hb5enitsj6ly5hx05qel7a2z1gb6y8vi4fd4l93}

Summary

The binary is a stripped OCaml native executable, but camlMain, camlProc_a_engine, and camlProc_b_engine were still present in the dynamic symbols. The actual verifier runs in the child process after fork(), not in the parent.

Analysis

The input must be 64 characters long and drawn from a fixed alphabet.

text
length   = 64
alphabet = abcdefghijklmnopqrstuvwxyz_0123456789!

OCaml immediate integers are encoded as (n << 1) | 1. The 0x81 used as the length comparison value in the disassembly means 64.

Both Proc_a_engine and Proc_b_engine follow an explode -> run -> collapse structure. run accumulates check closures, and the checks only run in the final collapse. The title, Until Executing, refers to this.

Each character is converted from ASCII to its alphabet index, stored as a tagged value.

text
a -> 1
b -> 3
c -> 5
...

I ported the current check and state update of Proc_b to Python to prune candidates. The branches shrank quickly until only one remained, and I verified that candidate again against the Proc_a checker.

The recovered internal string:

text
ovajumher0erwkl28_i8eecp!hb5enitsj6ly5hx05qel7a2z1gb6y8vi4fd4l93

Flag

hacktheon2026{ovajumher0erwkl28_i8eecp!hb5enitsj6ly5hx05qel7a2z1gb6y8vi4fd4l93}

Esc

Search titles, content and code.