Back to Blog

#10 Panoptisches Ereignis: XOR-Linearität bricht Fingerabdruck-Positionsverfahren

Code Auditing
February 13, 2026
8 min read

Am 25. August 2025 führte Panoptic mit Unterstützung von Cantina und Seal911 eine White-Hat-Rettungsaktion durch und sicherte etwa 400.000 US-Dollar an gefährdeten Geldern [1]. Die Grundursache war ein Fehler in der Konstruktion von s_positionsHash: Das Protokoll verwendete XOR, um Keccak256-Hashes von Positions-IDs zu einem einzigen Fingerabdruck zu aggregieren. Während einzelne Keccak256-Hashes kollisionsresistent bleiben, macht die mathematische Linearität von XOR den zusammengesetzten Fingerabdruck unsicher. Ein Angreifer kann eine Reihe gefälschter Positions-IDs generieren, deren XOR-aggregierter Hash mit jedem Ziel-Fingerabdruck übereinstimmt, wodurch die Positionsüberprüfung des Protokolls umgangen und Sicherheiten abgezogen werden, ohne Schulden zurückzuzahlen.

Hintergrund

Panoptic ist ein dezentrales Protokoll für den Handel mit ewigen Optionen, das auf Ethereum aufbaut und Benutzern den Handel mit Put- und Call-Optionen ermöglicht.

Die Funktion withdraw() hat einen Eingabeparameter positionList, der aus einer Menge von tokenIds besteht. Jede tokenId repräsentiert eine Position. Die Funktion withdraw() prüft den Schuldenstatus jeder Position basierend auf s_positionsHash und ruft dann die Sicherheiten des Benutzers ab.

Um Gas zu sparen, speichert das Protokoll nicht jede Position (d. h. tokenId) des Benutzers. Stattdessen berechnet es einen Fingerabdruck basierend auf allen tokenIds des Benutzers und zeichnet ihn in s_positionsHash auf. Die höchsten 8 Bits jedes s_positionsHash stellen numLegs dar, während die unteren 248 Bits den user position hash darstellen.

Für jede übergebene tokenId berechnet das Protokoll deren Hash, nimmt die unteren 248 Bits und aktualisiert den user position hash durch eine bitweise XOR-Operation mit den unteren 248 Bits des aktuellen s_positionsHash.

Gleichzeitig wird countLegs basierend auf dem numerischen Bereich der tokenId angepasst: Es bleibt unverändert, wenn die tokenId kleiner als 2642^{64} ist, und erhöht sich um 1, 2 oder 3, wenn sie in den Bereichen (264,2112)(2^{64}, 2^{112}), (2112,2168)(2^{112}, 2^{168}) bzw. (2168,2208)(2^{168}, 2^{208}) liegt. Dies wird schließlich in die obersten 8 Bits von s_positionsHash geschrieben, um numLegs zu aktualisieren.

Schwachstellenanalyse

Die Grundursache liegt in einem Fehler im Algorithmus des Vertrags zur Erstellung von s_positionsHash, insbesondere der Verwendung der XOR-Operation zur Aggregation von Keccak256-Hash-Ergebnissen. Während eine einzelne Hash-Funktion sicher bleibt, macht die mathematische Linearität der XOR-Operation den gesamten Fingerabdruck-Algorithmus (d. h. die XOR-Summe von Hashes) unsicher [2].

Linearität bedeutet, dass ein Angreifer die Hash-Funktion selbst nicht brechen muss (d. h. die tokenId aus dem Hash umkehren). Stattdessen können sie eine kombinatorische Strategie anwenden: die Generierung einer großen Anzahl zufälliger tokenIds, die Berechnung ihrer Keccak256(tokenId) und aus diesen Hash-Werten die Auswahl einer bestimmten Teilmenge, sodass die XOR-Summe dieser tokenId-Hashes exakt dem Ziel-Fingerabdruck des Opfers entspricht.

Dies ermöglicht es einem Angreifer, beim Aufruf von withdraw() eine Reihe gefälschter tokenIds zu übergeben, um den Gesundheitscheck zu bestehen und die gesamte Sicherheit zu erhalten, die s_positionsHash entspricht.

Theorie

Angenommen, der Positionsfingerabdruck s_positionsHash des Benutzers hat einen user position hash von TT und numLegs von kk mit Benutzer-tokenIds {t1,t2,,tn}\{t_1, t_2, \dots, t_n\}. Somit:

i=1k[Hash(ti)(mod2248)]=T\bigoplus_{i=1}^{k} [\text{Hash}(t_i) \pmod{2^{248}}] = T

Hier kann jeder 248-Bit-Hash-Wert als 248-dimensionaler Vektor betrachtet werden.

Hash(ti)(mod2248)=[b0,b1,,b247]T,wobei bi{0,1}\text{Hash}(t_i) \pmod{2^{248}} = [b_0, b_1, \dots, b_{247}]^T, wobei\ b_i \in \{0, 1\}

Daher liegt TT in einem 248-dimensionalen Raum, der aus 0en und 1en besteht (F2248\mathbb{F}_2^{248}). In diesem Raum ist die XOR-Operation äquivalent zur Vektoraddition (Anhang I).

Das Ziel des Angreifers ist es, nn 248-dimensionale Vektoren {v1,v2,,vn}\{v_1, v_2, \dots, v_n\} aus allen verfügbaren Vektoren zu finden, sodass die unteren 248 Bits ihrer XOR-Summe gleich TT sind. Somit können wir das Ziel des Angreifers als System linearer Gleichungen formulieren:

x1v1+x2v2++xnvn=Tx_1 v_1 + x_2 v_2 + \dots + x_n v_n = T

Insbesondere müssen wir TT nicht direkt konstruieren. Stattdessen wählen wir nn linear unabhängige Hash-Vektoren {v1,v2,,vn}\{v_1, v_2, \dots, v_n\} (wobei nn der Dimension 248 entspricht) und verwenden sie als Spaltenvektoren, um eine n×nn \times n-Matrix AA zu konstruieren:

A=[v1,v2,,vn]A = [v_1, v_2, \dots, v_n]

Das Problem verwandelt sich dann in die Suche nach einem Koeffizientenvektor xx, sodass:

Ax=TA \cdot x = T

Wobei x=[x1,x2,,xn]Tx = [x_1, x_2, \dots, x_n]^T und xi{0,1}x_i \in \{0, 1\}.

Gemäß der Theorie der linearen Algebra, solange die Matrix AA vollen Rang hat, spannt sie den gesamten nn-dimensionalen Raum auf. Das bedeutet, dass für jedes Ziel TT das Gleichungssystem eine eindeutige Lösung hat. Nach der Lösung von xx behalten wir einfach die Vektoren viv_i bei, für die xi=1x_i=1 gilt; ihre XOR-Summe ist TT.

Beispiel

Zur besseren Verständlichkeit demonstrieren wir diesen Konstruktionsprozess anhand einer Fallstudie. Angenommen, die Vektoren sind 3-dimensional, jede Dimension besteht nur aus 0 oder 1 und der Ziel-Hash-Wert ist 101, d. h. T=[1,0,1]TT = [1, 0, 1]^T.

Als Nächstes generieren wir zufällig 3 Hash-Werte:

  • v1=[1,1,0]Tv_1 = [1, 1, 0]^T
  • v2=[0,1,0]Tv_2 = [0, 1, 0]^T
  • v3=[0,1,1]Tv_3 = [0, 1, 1]^T

Wir konstruieren die Matrix AA mit diesen drei Vektoren als Spalten und stellen die Gleichung Ax=TAx=T auf:

[100111001][x1x2x3]=[101]\begin{bmatrix} 1 & 0 & 0 \\ 1 & 1 & 1 \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x_1 \\ x_2 \\ x_3 \end{bmatrix} = \begin{bmatrix} 1 \\ 0 \\ 1 \end{bmatrix}

Durch Gauß-Eliminierung erhalten wir x=[1,0,1]Tx = [1, 0, 1]^T. Das bedeutet, wir müssen v1v_1 und v3v_3 auswählen (entsprechend x1=1,x3=1x_1=1, x_3=1), und ihre XOR-Summe ergibt exakt TT.

Auswahl von n linear unabhängigen Vektoren

Wie bereits erwähnt, müssen wir zur Lösung von Ax=TAx=T eine vollrangige Matrix AA konstruieren. Da wir es mit einem extrem großen Vektorraum zu tun haben (m=2248m = 2^{248}), stellt sich die Kernfrage: Wie wählen wir schnell nn linear unabhängige Vektoren aus diesem riesigen Raum aus?

Betrachten wir die einfachste Methode: zufällige Generierung von nn tokenIds und Auswahl ihrer Hash-Ergebnisse als Vektoren.

Über F2\mathbb{F}_2 beträgt die Wahrscheinlichkeit PP, dass nn zufällig ausgewählte nn-dimensionale Vektoren eine vollrangige Matrix bilden:

P(n)=k=0n1(12k2n)P(n) = \prod_{k=0}^{n-1} \left(1 - \frac{2^k}{2^n}\right)

Wenn nn groß ist (in diesem Beispiel n=248n=248), konvergiert diese Wahrscheinlichkeit gegen eine Konstante (Anhang II):

limnP(n)0.28879\lim_{n \to \infty} P(n) \approx 0.28879

Das bedeutet, jeder zufällige Versuch hat eine Erfolgswahrscheinlichkeit von etwa 28,9 %. Im Durchschnitt benötigt ein Angreifer nur etwa 3,5 Versuche, um eine Menge linear unabhängiger Vektoren zu finden. Daher sind die Rechenkosten extrem gering, und der Angreifer kann schnell eine Matrix AA konstruieren, die die Bedingungen erfüllt.

Um countLegs in den obersten 8 Bits zu steuern, müssen wir nur den Bereich der zufällig generierten tokenId-Werte basierend auf dem Ziel-countLegs anpassen.

Wenn wir beispielsweise möchten, dass numLegs im gefälschten Fingerabdruck 0 ist, stellen wir einfach sicher, dass die nn zufällig generierten tokenIds kleiner als 2642^{64} sind. Da die Beinvermehrung für tokenIds in diesem Bereich 0 ist, wird die endgültige akkumulierte numLegs zwangsläufig 0 sein, unabhängig davon, welche Vektoren die Gauß-Eliminierungslösung xx auswählt.

Angriffsanalyse

Der White-Hat-Retter initiierte mehrere Rettungstransaktionen. Der Einfachheit halber basiert die folgende Diskussion auf einer einzigen dieser Transaktionen [3].

Die Kernlogik besteht aus den folgenden 5 Schritten:

  1. Leihen von 0,23e8 WBTC und 28e18 WETH über einen Flash-Loan von Aave.
  2. Einzahlung von 0,23e8 WBTC und 28e18 WETH in den poWBTC-Vertrag und den 0x1f8d_poWETH-Vertrag.
  3. Aufruf von mintOptions() des PanopticPool-Vertrags mit einer normalen positionIdList, um Gelder zu leihen und eine gehebelte Position zu eröffnen.
  4. Aufruf von withdraw() unter Übergabe der gefälschten tokenIds. Da diese gefälschten Positionen eine positionSize von 0 haben, gibt die Funktion tokenRequired als 0 zurück, was bedeutet, dass die für alle Positionen erforderliche Gesamtsicherheit fälschlicherweise als null berechnet wird. In der Zwischenzeit ist der von diesen tokenIds generierte s_positionsHash exakt derselbe wie der in Schritt 3 generierte, was es dem Retter ermöglicht, alle Sicherheiten ohne Rückzahlung von Schulden abzuziehen.
  5. Rückzahlung des Flash-Loans und Ausführung der nächsten Runde.

Zusammenfassung

Dieser Vorfall hebt zwei sich gegenseitig verstärkende Fehler hervor, die zusammen einen unbefugten Abzug von Sicherheiten ermöglichten.

  • XOR ist keine sichere Aggregationsfunktion für Hashes. Keccak256 ist kollisionsresistent, aber die Linearität von XOR bedeutet, dass die XOR-Summe mehrerer Hashes diese Eigenschaft nicht erbt. Die Konstruktion einer Menge von Eingaben, deren Hashes zu einem beliebigen Zielwert XOR-summiert werden, reduziert sich auf die Lösung eines Systems linearer Gleichungen über F2\mathbb{F}_2, was rechnerisch trivial ist. Hash-Komposition erfordert Operationen, die die Kollisionsresistenz erhalten, wie z. B. Konkatenation gefolgt von Neuhash.
  • Fehlende Validierung von Positions-IDs. Das Protokoll überprüfte nicht, ob übergebene positionIds gültigen Optionspositionen entsprachen. Werte unter 2642^{64} tragen einen countLegs von 0 und eine positionSize von 0, was bedeutet, dass die gefälschten Positionen keine Schulden verursachen. Dies ermöglichte es dem Angreifer, den Gesundheitscheck mit einer Sicherheitenanforderung von Null zu bestehen und gleichzeitig den Ziel-Fingerabdruck zu matchen.

Referenz

  1. https://x.com/Panoptic_xyz/status/1961187739866644524

  2. https://cseweb.ucsd.edu/~mihir/papers/inchash.pdf

  3. https://app.blocksec.com/explorer/tx/eth/0x67a45dfe5ff4b190058674d7c791bbdc48e889f319f937c24fa13a5f9093f088

Anhang

Die folgenden beiden Anhänge bieten eine mathematische Erklärung und einen Beweis für die Aussagen im Haupttext, nämlich dass die XOR-Operation äquivalent zur Vektoraddition ist (Anhang I) und die Wahrscheinlichkeit, dass eine zufällige Matrix vollen Rang hat (Anhang II).

Anhang I

Im endlichen Körper F2={0,1}\mathbb{F}_2 = \{0, 1\} ist die Addition als Addition modulo 2 definiert:

0+0=00+1=11+0=11+1=0(mod2)\begin{aligned} 0 + 0 &= 0 \\ 0 + 1 &= 1 \\ 1 + 0 &= 1 \\ 1 + 1 &= 0 \pmod 2 \end{aligned}

Die Beobachtung zeigt, dass dies identisch mit der logischen Operation Exklusiv-Oder (XOR, Symbol \oplus) ist.

Für den nn-dimensionalen Vektorraum F2n\mathbb{F}_2^n (in diesem Fall n=248n=248) ist die Addition zweier Vektoren u=[u1,,un]Tu = [u_1, \dots, u_n]^T und v=[v1,,vn]Tv = [v_1, \dots, v_n]^T als komponentenweise Addition modulo 2 definiert:

u+v=[u1+v1(mod2)un+vn(mod2)]=[u1v1unvn]=uvu + v = \begin{bmatrix} u_1 + v_1 \pmod 2 \\ \vdots \\ u_n + v_n \pmod 2 \end{bmatrix} = \begin{bmatrix} u_1 \oplus v_1 \\ \vdots \\ u_n \oplus v_n \end{bmatrix} = u \oplus v

Daher ist im Vektorraum F2n\mathbb{F}_2^{n} die Vektoraddition äquivalent zur bitweisen XOR-Operation auf den Vektorkomponenten.

Anhang II

Um die Matrix vollrangig zu machen, müssen diese nn Vektoren linear unabhängig sein.

Der erste Vektor v1v_1 kann jeder Vektor in F2n\mathbb{F}_2^n außer dem Nullvektor sein, was 2n12^n - 1 Auswahlmöglichkeiten bietet; der zweite Vektor v2v_2 darf nicht im von {v1}\{v_1\} aufgespannten Unterraum liegen, der 212^1 Vektoren enthält, was 2n22^n - 2 Auswahlmöglichkeiten übrig lässt; dieser Logik folgend darf der kk-te Vektor vkv_k nicht im von den vorherigen k1k-1 Vektoren aufgespannten Unterraum liegen, was zu 2n2k12^n - 2^{k-1} möglichen Auswahlmöglichkeiten führt.

Die Gesamtzahl solcher Matrizen (d. h. die Ordnung von GL(n,F2)GL(n, \mathbb{F}_2)) ist:

N=k=0n1(2n2k)=(2n1)(2n2)(2n4)(2n2n1)N = \prod_{k=0}^{n-1} (2^n - 2^k) = (2^n - 1)(2^n - 2)(2^n - 4)\cdots(2^n - 2^{n-1})

Und die Gesamtzahl aller möglichen n×nn \times n-Matrizen ist (2n)n=2n2(2^n)^n = 2^{n^2}.

Somit ist die Wahrscheinlichkeit PP:

P=k=0n1(2n2k)2n2=k=0n1(2n2k2n)=k=0n1(12k2n)P = \frac{\prod_{k=0}^{n-1} (2^n - 2^k)}{2^{n^2}} = \prod_{k=0}^{n-1} \left( \frac{2^n - 2^k}{2^n} \right) = \prod_{k=0}^{n-1} (1 - \frac{2^k}{2^n})

Wenn wir j=nkj = n - k setzen, können wir diesen Ausdruck umschreiben als:

P=j=1n(112j)P = \prod_{j=1}^{n} \left(1 - \frac{1}{2^j}\right)

Wenn nn \to \infty, konvergiert dieses Produkt gegen eine Konstante:

P0.288788P \approx 0.288788

Das bedeutet, dass für große nn die Wahrscheinlichkeit, dass eine zufällige Matrix vollen Rang hat, etwa 28,9 % beträgt.


Über BlockSec

BlockSec ist ein Anbieter von Blockchain-Sicherheit und Krypto-Compliance. Wir entwickeln Produkte und Dienstleistungen, die Kunden bei der Durchführung von Code-Audits (einschließlich Smart Contracts, Blockchain und Wallets), der Echtzeit-Abwehr von Angriffen, der Analyse von Vorfällen, der Verfolgung illegaler Gelder und der Erfüllung von AML/CFT-Verpflichtungen während des gesamten Lebenszyklus von Protokollen und Plattformen unterstützen.

BlockSec hat mehrere Blockchain-Sicherheitsarbeiten auf renommierten Konferenzen veröffentlicht, mehrere Zero-Day-Angriffe von DeFi-Anwendungen gemeldet, mehrere Hackerangriffe blockiert, um mehr als 20 Millionen Dollar zu retten, und Kryptowährungen im Wert von mehreren Milliarden Dollar gesichert.

Sign up for the latest updates
Newsletter - April 2026
Security Insights

Newsletter - April 2026

In April 2026, the DeFi ecosystem experienced three major security incidents. KelpDAO lost ~$290M due to an insecure 1-of-1 DVN bridge configuration exploited via RPC infrastructure compromise, Drift Protocol suffered ~$285M from a multisig governance takeover leveraging Solana's durable nonce mechanism, and Rhea Finance incurred ~$18.4M following a business logic flaw in its margin-trading module that allowed circular swap path manipulatio

~$7.04M Lost: GiddyDefi, Volo Vault & More | BlockSec Weekly
Security Insights

~$7.04M Lost: GiddyDefi, Volo Vault & More | BlockSec Weekly

This BlockSec weekly security report covers eight attack incidents detected between April 20 and April 26, 2026, across Ethereum, Avalanche, Sui, Base, HyperLiquid, and MegaETH, with total estimated losses of approximately $7.04M. The highlighted incident is the $1.3M GiddyDefi exploit, where the attacker did not break any cryptography or use a flash loan but simply replayed an existing on-chain EIP-712 signature with the unsigned `aggregator` and `fromToken` fields swapped out for a malicious contract, demonstrating how partial signature coverage turns any historical signature into a generic permit. Other incidents include a $3.5M Volo Vault operator key compromise on Sui, a $1.5M Purrlend privileged-role takeover, a $413K SingularityFinance oracle misconfiguration, a $142.7K Scallop cross-pool index injection, a $72.35K Kipseli Router decimal mismatch, a $50.7K REVLoans (Juicebox) accounting pollution, and a $64K Custom Rebalancer arbitrary-call exploit.

Weekly Web3 Security Incident Roundup | Apr 13 – Apr 19, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Apr 13 – Apr 19, 2026

This BlockSec weekly security report covers four attack incidents detected between April 13 and April 19, 2026, across multiple chains such as Ethereum, Unichain, Arbitrum, and NEAR, with total estimated losses of approximately $310M. The highlighted incident is the $290M KelpDAO rsETH bridge exploit, where an attacker poisoned the RPC infrastructure of the sole LayerZero DVN to fabricate a cross-chain message, triggering a cascading WETH freeze across five chains and an Arbitrum Security Council forced state transition that raises questions about the actual trust boundaries of decentralized systems. Other incidents include a $242K MMR proof forgery on Hyperbridge, a $1.5M signed integer abuse on Dango, and an $18.4M circular swap path exploit on Rhea Finance's Burrowland protocol.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit