Back to Blog

#10 Panoptik Olay: XOR Doğrusallığı Konum Parmak İzi Şemasını Bozuyor

Code Auditing
February 13, 2026
7 min read

25 Ağustos 2025'te Cantina ve Seal911'in yardımıyla Panoptic, yaklaşık 400.000 dolarlık risk altındaki fonları güvence altına alan bir beyaz şapka kurtarma operasyonu gerçekleştirdi [1]. Temel neden, s_positionsHash oluşturma sürecindeki bir kusurdu: protokol, pozisyon ID'lerinin Keccak256 hash'lerini tek bir parmak izinde toplamak için XOR kullandı. Bireysel Keccak256 hash'leri çarpışmaya dirençli olmaya devam etse de XOR'un matematiksel doğrusallığı, bileşik parmak izini güvensiz kılar. Bir saldırgan, XOR ile toplanmış hash'i herhangi bir hedef parmak iziyle eşleşen sahte pozisyon ID'leri oluşturabilir; böylece protokolün pozisyon doğrulamasını atlatarak borcu geri ödemeden teminatı çekebilir.

Arka Plan

Panoptic, kullanıcıların put ve call opsiyonları işlem yapmasına olanak tanıyan, Ethereum üzerine inşa edilmiş merkeziyetsiz bir sürekli opsiyon işlem protokolüdür.

withdraw() fonksiyonunun positionList adlı bir giriş parametresi vardır; bu parametre bir dizi tokenId'den oluşur. Her tokenId bir pozisyonu temsil eder. withdraw() fonksiyonu, her pozisyonun borç durumunu s_positionsHash değerine göre kontrol eder ve ardından kullanıcının teminatını geri alır.

Gaz tasarrufu amacıyla protokol, kullanıcının her pozisyonunu (yani tokenId'yi) depolamaz. Bunun yerine, kullanıcının tüm tokenId'lerine dayalı bir parmak izi hesaplar ve bunu s_positionsHash içinde kaydeder. Her s_positionsHash değerinin en anlamlı 8 biti numLegs'i, alt 248 biti ise kullanıcı pozisyon hash'ini temsil eder.

Geçirilen her tokenId için protokol, hash'ini hesaplar, alt 248 biti alır ve mevcut s_positionsHash değerinin alt 248 biti ile bit düzeyinde XOR işlemi gerçekleştirerek kullanıcı pozisyon hash'ini günceller.

Aynı zamanda countLegs, tokenId'nin sayısal aralığına göre ayarlanır: tokenId 2642^{64}'ün altındayken değişmez; (264,2112)(2^{64}, 2^{112}), (2112,2168)(2^{112}, 2^{168}) ve (2168,2208)(2^{168}, 2^{208}) aralıklarında sırasıyla 1, 2 veya 3 artış gösterir. Bu değer son olarak s_positionsHash değerinin üst 8 bitine yazılarak numLegs güncellenir.

Güvenlik Açığı Analizi

Temel neden, sözleşmenin s_positionsHash oluşturma algoritmasındaki bir kusurdur; özellikle Keccak256 hash sonuçlarını toplamak için XOR işleminin kullanılması bu soruna yol açmaktadır. Tek bir hash fonksiyonu güvenli olmaya devam etse de XOR işleminin matematiksel doğrusallığı, genel parmak izi algoritmasını (yani hash'lerin XOR toplamını) güvensiz kılar [2].

Doğrusallık, bir saldırganın hash fonksiyonunu kendisini kırmasına (yani tokenId'yi hash'ten tersine çevirmesine) gerek olmadığı anlamına gelir. Bunun yerine kombinatoryal bir strateji kullanabilir: çok sayıda rastgele tokenId oluşturarak Keccak256(tokenId) hesaplar ve bu hash değerlerinden, tokenId hash'lerinin XOR toplamının hedef parmak iziyle tam olarak eşleştiği belirli bir alt küme seçer.

Bu sayede saldırgan, withdraw() çağrısında bir dizi sahte tokenId geçirerek sağlık kontrolünü atlayabilir ve s_positionsHash değerine karşılık gelen tüm teminatı geri alabilir.

Teori

Kullanıcının pozisyon parmak izi s_positionsHash değerinin kullanıcı pozisyon hash'inin TT, numLegs değerinin ise kk olduğunu ve kullanıcının tokenId'lerinin {t1,t2,,tn}\{t_1, t_2, \dots, t_n\} olduğunu varsayalım. Bu durumda:

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

Burada her 248-bitlik hash değeri 248 boyutlu bir vektör olarak görülebilir.

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

Dolayısıyla TT, 0 ve 1'lerden oluşan 248 boyutlu bir uzayda (F2248\mathbb{F}_2^{248}) yer alır. Bu uzayda XOR işlemi, vektör toplamaya eşdeğerdir (Ek I).

Saldırganın amacı, mevcut tüm vektörler arasından XOR toplamlarının alt 248 bitinin TT'ye eşit olduğu nn adet 248 boyutlu vektör {v1,v2,,vn}\{v_1, v_2, \dots, v_n\} bulmaktır. Bu nedenle saldırganın hedefini bir doğrusal denklem sistemi olarak şu şekilde ifade edebiliriz:

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

Özellikle, TT'yi doğrudan oluşturmaya çalışmamıza gerek yoktur. Bunun yerine nn adet doğrusal bağımsız hash vektörü {v1,v2,,vn}\{v_1, v_2, \dots, v_n\} (burada nn, boyut olan 248'e eşittir) seçer ve bunları sütun vektör olarak kullanarak n×nn \times n boyutunda bir AA matrisi oluştururuz:

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

Problem artık şu şekilde dönüşür: şunu sağlayan bir katsayı vektörü xx bulmak:

Ax=TA \cdot x = T

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

Doğrusal cebir teorisine göre, AA matrisi tam ranklı olduğu sürece tüm nn boyutlu uzayı kapsar. Bu, herhangi bir TT hedefi için denklem sisteminin benzersiz bir çözüme sahip olduğu anlamına gelir. xx için çözüm bulunduktan sonra, yalnızca xi=1x_i=1 olan viv_i vektörlerini tutmamız yeterlidir; bunların XOR toplamı TT'ye eşittir.

Örnek

Anlayışı kolaylaştırmak için bu oluşturma sürecini bir örnek çalışmayla gösteriyoruz. Vektörlerin 3 boyutlu olduğunu, her boyutun yalnızca 0 veya 1'den oluştuğunu ve hedef hash değerinin 101, yani T=[1,0,1]TT = [1, 0, 1]^T olduğunu varsayalım.

Ardından rastgele 3 hash değeri oluşturuyoruz:

  • 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

Bu üç vektörü sütun olarak kullanarak AA matrisini oluşturuyoruz ve Ax=TAx=T denklemini kuruyoruz:

[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}

Gauss eleme yöntemiyle çözersek x=[1,0,1]Tx = [1, 0, 1]^T elde ederiz. Bu, v1v_1 ve v3v_3'ü seçmemiz gerektiği (x1=1,x3=1x_1=1, x_3=1'e karşılık gelir) ve XOR toplamlarının hedef TT'ye tam olarak eşit olduğu anlamına gelir.

n Adet Doğrusal Bağımsız Vektör Seçimi

Daha önce belirtildiği üzere, Ax=TAx=T'yi çözmek için tam ranklı bir AA matrisi oluşturmamız gerekir. Son derece büyük bir vektör uzayıyla (m=2248m = 2^{248}) çalıştığımız göz önüne alındığında, temel soru şudur: Bu geniş uzaydan nn adet doğrusal bağımsız vektörü nasıl hızlıca seçeriz?

En basit yöntemi düşünelim: rastgele nn adet tokenId oluşturmak ve bunların hash sonuçlarını vektör olarak seçmek.

F2\mathbb{F}_2 üzerinde, rastgele seçilen nn adet nn boyutlu vektörün tam ranklı bir matris oluşturma olasılığı PP:

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

nn büyük olduğunda (bu örnekte n=248n=248), bu olasılık bir sabite yakınsar (Ek II):

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

Bu, her rastgele denemenin yaklaşık %28,9 başarı olasılığına sahip olduğu anlamına gelir. Ortalamada, bir saldırganın doğrusal bağımsız vektörler kümesi bulmak için yalnızca yaklaşık 3,5 denemeye ihtiyacı vardır. Bu nedenle hesaplama maliyeti son derece düşüktür ve saldırgan, koşulları sağlayan bir AA matrisini hızla oluşturabilir.

Üst 8 bitteki countLegs değerini kontrol etmek için, hedef countLegs değerine göre rastgele oluşturulan tokenId değerlerinin aralığını ayarlamamız yeterlidir.

Örneğin, sahte parmak izindeki numLegs değerinin 0 olmasını istiyorsak, oluşturulan nn adet rastgele tokenId'nin tamamının 2642^{64}'ten küçük olmasını sağlamamız yeterlidir. Bu aralıktaki tokenId'ler için bacak artışı 0 olduğundan, Gauss eleme çözümünün xx seçtiği vektörlerden bağımsız olarak, nihai birikimli numLegs değeri kaçınılmaz biçimde 0 olacaktır.

Saldırı Analizi

Beyaz şapkalı kurtarıcı birden fazla kurtarma işlemi başlattı. Basitlik açısından aşağıdaki tartışma yalnızca bu işlemlerden birine dayanmaktadır [3].

Temel mantık aşağıdaki 5 adımdan oluşmaktadır:

  1. Aave'den flash loan aracılığıyla 0,23e8 WBTC ve 28e18 WETH borç alınır.
  2. 0,23e8 WBTC ve 28e18 WETH, poWBTC sözleşmesine ve 0x1f8d_poWETH sözleşmesine yatırılır.
  3. PanopticPool sözleşmesinin mintOptions() fonksiyonu, normal bir positionIdList ile çağrılarak fon borç alınır ve kaldıraçlı bir pozisyon açılır.
  4. withdraw() çağrılarak sahte tokenId'ler geçirilir. Bu sahte pozisyonların positionSize değeri 0 olduğundan fonksiyon, tokenRequired değerini 0 olarak döndürür; yani tüm pozisyonlar için gereken toplam teminat hatalı biçimde sıfır olarak hesaplanır. Bu arada, bu tokenId'lerin oluşturduğu s_positionsHash değeri, 3. adımda oluşturulanla tam olarak aynıdır; bu da kurtarıcının herhangi bir borcu geri ödemeden tüm teminatı geri almasına olanak tanır.
  5. Flash loan geri ödenir ve bir sonraki tur başlatılır.

Özet

Bu olay, yetkisiz teminat çekimine olanak tanıyan iki birleşik kusuru gün yüzüne çıkarmaktadır.

  • XOR, hash'ler için güvenli bir toplama fonksiyonu değildir. Keccak256 çarpışmaya dirençlidir; ancak XOR'un doğrusallığı, birden fazla hash'in XOR toplamının bu özelliği miras alamayacağı anlamına gelir. Hash'leri herhangi bir hedef değerle XOR'layacak bir girdi kümesi oluşturmak, F2\mathbb{F}_2 üzerinde bir doğrusal denklem sistemi çözümüne indirgenir; bu da hesaplama açısından son derece basittir. Hash kompozisyonu, çarpışma direncini koruyan işlemler gerektirmektedir; örneğin birleştirme ve ardından yeniden hash'leme gibi.
  • Pozisyon ID'lerinin doğrulanmaması. Protokol, geçirilen positionId'lerin geçerli opsiyon pozisyonlarına karşılık gelip gelmediğini doğrulamadı. 2642^{64}'ün altındaki değerler 0 countLegs ve 0 positionSize taşıdığından, sahte pozisyonlar borç oluşturmuyordu. Bu durum, saldırganın hedef parmak iziyle eşleşirken sıfır teminat gereksinimiyle sağlık kontrolünü geçmesine olanak tanıdı.

Referans

  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

Ek

Aşağıdaki iki ek, ana metindeki ifadeler için matematiksel bir açıklama ve kanıt sunmaktadır: XOR işleminin vektör toplamaya eşdeğer olduğu (Ek I) ve rastgele bir matrisin tam ranklı olma olasılığı (Ek II).

Ek I

F2={0,1}\mathbb{F}_2 = \{0, 1\} sonlu alanında toplama, modül 2 toplama olarak tanımlanır:

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}

Bu işlemin Dışlayan VEYA (XOR, sembol \oplus) mantıksal işlemiyle özdeş olduğu görülmektedir.

nn boyutlu F2n\mathbb{F}_2^n vektör uzayı için (bu durumda n=248n=248), u=[u1,,un]Tu = [u_1, \dots, u_n]^T ve v=[v1,,vn]Tv = [v_1, \dots, v_n]^T iki vektörünün toplamı, bileşen bazında modül 2 toplama olarak tanımlanır:

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

Dolayısıyla F2n\mathbb{F}_2^{n} vektör uzayında vektör toplamı, vektör bileşenleri üzerindeki bit düzeyinde XOR işlemine eşdeğerdir.

Ek II

Matrisin tam ranklı olabilmesi için bu nn vektörün doğrusal bağımsız olması gerekir.

İlk vektör v1v_1, F2n\mathbb{F}_2^n içinde sıfır vektörü dışında herhangi bir vektör olabilir; bu da 2n12^n - 1 seçenek sunar. İkinci vektör v2v_2, {v1}\{v_1\} tarafından gerilen alt uzayda yer almamalıdır; bu alt uzay 212^1 vektör içerir ve 2n22^n - 2 seçenek bırakır. Bu mantığa göre kk'inci vektör vkv_k, önceki k1k-1 vektör tarafından gerilen alt uzayda yer alamaz; bu da 2n2k12^n - 2^{k-1} olası seçenek sunar.

Bu tür matrislerin toplam sayısı (yani GL(n,F2)GL(n, \mathbb{F}_2)'nin mertebesi) şöyledir:

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})

Tüm olası n×nn \times n matrislerin toplam sayısı ise (2n)n=2n2(2^n)^n = 2^{n^2}'dir.

Dolayısıyla PP olasılığı şöyle ifade edilir:

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})

j=nkj = n - k dönüşümüyle bu ifadeyi şu şekilde yeniden yazabiliriz:

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

nn \to \infty iken bu çarpım bir sabite yakınsar:

P0.288788P \approx 0.288788

Bu, büyük nn değerleri için rastgele bir matrisin tam ranklı olma olasılığının yaklaşık %28,9 olduğu anlamına gelir.


BlockSec Hakkında

BlockSec, tam yığın blok zinciri güvenliği ve kripto uyumluluk sağlayıcısıdır. Müşterilerin kod denetimi (akıllı sözleşmeler, blok zinciri ve cüzdanlar dahil) gerçekleştirmesine, saldırıları gerçek zamanlı olarak engellenmesine, olayları analiz etmesine, yasadışı fonları takip etmesine ve protokoller ile platformların tam yaşam döngüsü boyunca AML/CFT yükümlülüklerini karşılamasına yardımcı olan ürün ve hizmetler geliştiriyoruz.

BlockSec, saygın konferanslarda birden fazla blok zinciri güvenlik makalesi yayımlamış, DeFi uygulamalarının çeşitli sıfır gün saldırılarını raporlamış, 20 milyon dolardan fazlayı kurtarmak için birden fazla saldırıyı engellemiş ve milyarlarca dolarlık kripto para birimini güvence altına almıştır.

Best Security Auditor for Web3

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

BlockSec Audit