Bala & Atibala: The Forgotten State

By Team Cryptonite · 2 min read

About the CTF: Pinaka CTF

The warden attests one record and then honours a different record that flattens to the same bytes. The goal is to get an "elevated" record (mantra=atibala, tier>=7) accepted using the attestation of a harmless one.

Bala & Atibala: The Forgotten State

**Pinaka CTF 2026** · Reverse engineering · Team Cryptonite · All 44 Pinaka write-ups


Category: misc / canonicalization

Flag: PINAKA{balaatibalatheflattenedrecord_forgets}

Overview

The warden attests one record and then honours a different record that flattens to the same bytes. The goal is to get an "elevated" record (mantra=atibala, tier>=7) accepted using the attestation of a harmless one.

Files and components:

Analysis

A boon record is an ordered list of [key, value] string pairs, and duplicates are allowed. The Kotlin boundary serializes it with no escaping, so = and & inside a key or value are written as-is:


fun serialize(rec: Record): ByteArray {
    val sb = StringBuilder()
    for ((k, v) in rec.pairs) { sb.append(k); sb.append('='); sb.append(v); sb.append('&') }
    return sb.toString().toByteArray(Charsets.UTF_8)
}

The check for "is this record supreme?" looks at the pairs list, not the bytes:


fun checkElevated(rec: Record): Boolean {
    val m = rec.pairs.any { it.first == "mantra" && it.second == "atibala" }
    val t = rec.pairs.any { it.first == "tier" && (it.second.toIntOrNull() ?: 0) >= 7 }
    return m && t
}

nativeAttest(serialize(rec)) runs the bytecode with the warden key, which isn't in any player file, so the state can't be computed locally. That doesn't matter: the warden computes it for a non-elevated record, and a collision makes that state valid for an elevated one.

the Kotlin serialize() and checkElevated() source side by side

Solution

Two records with different pair structures serialize to identical bytes:

checkElevated(A) is false: A has one pair whose key is the literal string mantra=atibala&tier, so there is no mantra key and no tier key, and the warden attests it. checkElevated(B) is true. Since serialize(A) == serialize(B), the attestation output is identical, so A's attested state can be presented with B.

Submission

Petition with record A:


POST /ashram/petition
{"pairs":[["mantra=atibala&tier","7"]]}

{"attested_state":"4ce21f87d685eba923a22160f8e17f70","status":"attested"}

Claim with record B, reusing that state:


POST /ashram/claim
{"pairs":[["mantra","atibala"],["tier","7"]],"attested_state":"4ce21f87d685eba923a22160f8e17f70"}

{"flag":"PINAKA{bala_atibala_the_flattened_record_forgets}","proclamation":"Vishwamitra honours the forgotten boon of Atibala","status":"granted"}

Notes

Read this post on CyberHx →