看雪.紐盾 KCTF 2019 Q2 | 第十題點評及解題思路
“池塘邊的榕樹上,知了在聲聲叫著夏天~”伴著窗外綠葉間的蟬鳴,我們迎來週五的夕陽,於此同時,我們看雪紐盾KCTF的Q2賽題解析也到達尾聲。
此刻,小夥伴們有沒有一丟丟不捨和眷戀呢?沒關係,我們的KCTF第三賽段在九月火熱開啟,等你來戰!
今天我們來看下第十題,觀英雄鬥智鬥勇,開啟時間之輪,逆轉乾坤~
題目簡介
題目背景:
歷經千辛萬苦,集齊所有的能量寶石,但成功開啟時間之輪,開啟進入另一個平行時空的入口,還差一步。
你需要將這八顆寶石按照正確的順序排列出來,才能夠成功開啟時間之輪,否則能量寶石也只是八塊石頭……
快來尋找寶石排列的秘密吧!人類的命運如今就掌握在你的手中。
本題共有1990人圍觀,截至比賽結束只有5人攻破此題。縱觀全域性,十道題目中難度排名前三,難倒了不少英雄好漢。
攻破此題的戰隊一覽:
接下來我們來對題目進行詳細解析。
看雪評委crownless點評
本題演算法基於二次剩餘與離散對數,主要涉及公鑰密碼學的知識。解決此題的關鍵在於,不僅要掌握紮實的密碼學、數學知識,而且還要懂逆向分析、程式分析。
出題團隊簡介
本題出題戰隊 ReadPage :
論壇ID為readyu,畢業於中國科學技術大學自動控制專業,從事軟體開發多年。在軟體保護技術、加密演算法方面有一些體驗。曾在北京多看科技從事電子閱讀加密技術的研究,以及在MIUI從事系統安全方面工作。
設計思路
本題演算法主要涉及公鑰密碼學的基礎知識。Win32程式, 無殼, 無Anti。暫定取名 “一石二鳥”。
一、序列號
本題唯一序列號SN為:
KCTFREADYKXXXX1548396171915056368526513804948765619094392315806578461796159505215278288254
二、方程
演算法基於二次剩餘與離散對數, 建立了2個方程 (1) (2) 見下文,並且模同一個素數,所以暫定取名 “一石二鳥”。
P=2^255-19 是一個素數,base16 或者base10如下:
P(hex)=7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED
P(dec)=57896044618658097711785492504343953926634992332820282019728792003956564819949
序列號格式為兩段字元, + 表示字串合併:
SN = “s1” + “XXXX” + “s2”
s1是大寫字母串, s2是十進位制數字串。數值上, 1 < s1, s2 < P
其中,s1,s2 是未知量, d是s1變換而來的未知量。
s1逆序變換,加上最小位調整, 然後base25解碼得到d. (Y,G)內建於程式之中。
64*(s2-s1)^4 + (s2-s1)^2 + 3 = s1 mod P ... (1)
G^d = Y mod P ... (2)
G,Y 是已知數, 範圍 [ 1, P-1]:
Y = 100
G = 9230197858975018299629857977411527954550899478307510809210520967346958600039
三、解法
解法:首先解方程2,得到d,轉換為s1 ;然後再解方程1,得到s2。
3.1 解方程(2)
方程(2)解釋如下:
d = base25.reverse(s1) ....(3)
隨機驗證任何一對,結果都是一樣的。
(Y,G) =
"100,9230197858975018299629857977411527954550899478307510809210520967346958600039",
"101,50414221767352083765613498524674590844333823720255656432490557866777248860034",
"102,38377684164112914669201831650756813551072223314592288217929947158283532270268",
"103,13436195533519778671648120865743178010431697022400670384909515001970400645091",
比如 Y=100,
G=9230197858975018299629857977411527954550899478307510809210520967346958600039
G^d = Y mod P , P是256bit的大素數。
表面一看,需要解256 bit的離散對數, 需要解離散對數工具,比如gdlog。
GDLOG
Implementation of the GNFS for discrete logarithm problem in GF(p)
https://sourceforge.net/projects/gdlog/
但本題,程式裡給出了條件,d 轉化為base25字元時,最長為10個位元組。
所以數量級極大地縮小,只有47bits。也就是d < limit, limit = 25^10 = 95367431640625 。
因此,用pollard kangaroo 演算法求解d,範圍為band = (1, 95367431640625) 只有47 bits。
kangaroo演算法是解決區間band = (a, b)上離散對數問題很有效的方法,在平均意義下需要進行2 * √|a-b|次群操作。
期望步數 2 *(limit^0.5)= 2* 9765625, 也就是大概2000萬次。經測試, 大概30-60秒之間。
我們得到:
d(dec) = 79821823136933
d(hex)= 4898F769D4A5
base25table=ABCDEFGHKJILMNOPQRSTUVWYZ
是26個大寫字母表,(扣除X, 並且K,I互換位置),得到 d.base25 = UYDAERFTCK
逆序後得到:s = d.base25.reverse = KCTFREADYU
為了防止被猜測到s1, 低位做了修正,修正值 diff = 'U' - 'K' = 10:
註冊碼裡的採用KCTFREADYK,
s1 = KCTFREADYK + diff = KCTFREADYU
s1(hex) = 4B435446524541445955
3.2 解方程(1)
首先,根據一般的二次剩餘方程, 可以配方以後求解:
a*x^2 + bx + c = 0 mod p
兩邊乘以4a配方:
4a^2*x^2 + 4a*bx + 4ac = 0 mod p
方程變為
(2a*x + b)^2 = b^2 - 4ac
令delta = b^2 - 4ac, 就可以歸結為求 sqroot(delta) mod p:
x1 = (-b - sqroot(delta))/(2a) mod p
x2 = (-b + sqroot(delta))/(2a) mod p
注意,這裡的除法是模P的逆。
方程(1)解釋如下:
64*(s2 - s1)^4 + (s2-s1)^2 + 3 - s1 = 0 mod P
F(x)是一個4次多項式:F(x) = a4*x^4 + a2*x^2 + a0
這裡取x = s2 - s1, a4 = 64, a2 = 1, a0 = 3
F(x) 可以簡化為一個二次剩餘方程,
64*(s2 - s1)^4 + (s2-s1)^2 + 3 = s1 mod P ... (4)
64*r^2 + r + 3 = s1 mod p ,
=> 64*r^2 + r = (s1 - 3) mod p
兩邊乘以4a,加上1:
4*64*64*r^2 + 256*r + 1 = 256*(s1-3) + 1 mod p
(128r + 1)^2 = 256*(s1-3) + 1 mod p
s1 = 4B435446524541445955, s1-3 = 4B435446524541445952
乘以256就是左移一個位元組。
方程簡化為:
(128r + 1)^2 = 4B43544652454144595201 mod p ...(5)
r = (sqroot(4B43544652454144595201, P) - 1)/128
第一步,方程(5)求解首先求得兩個解r1,r2。
Y = 4B43544652454144595201
sqroot(Y, P), RDLP 求解。
Two sqroots of Y (mod P), in HEX BASE.
G1-258B783A22015B08A6C64FB55644BAACCDA201473D4B6786821056707C680B58
G2-5A7487C5DDFEA4F75939B04AA9BB4553325DFEB8C2B498797DEFA98F8397F495
再求得:
r1=2D4B16F0744402B6114D8C9F6AAC8975599B44028E7A96CF0D0420ACE0F8D010
r2=1CB4E90F8BBBFD49EEB273609553768AA664BBFD71856930F2FBDF531F072FE5
然後r1,r2分別求解二次剩餘,各有兩個解,所以一共有4個解。
第二步,解出 x^2 = r mod p,可用RDLP求解。
root(r1)=
x2-3CCA260F45B79993C67F35F7A716B28BBA591BA35593C8DEB9B959C2CE43AE21
x3-4335D9F0BA48666C3980CA0858E94D7445A6E45CAA6C37214646A63D31BC51CC
root(r2)=
x4-7C93A389F44E31BC25D90165624292389B47C2C27F60286FF627A6FC3DB84BC4
x1-036C5C760BB1CE43DA26FE9A9DBD6DC764B83D3D809FD79009D85903C247B429
這4個解記作x1,x2,x3,x4, 恰好每一個都分佈在(1, P)的4個區間之一。
(0-1/4), (1/4-1/2), (1/2 - 3/4), (3/4, 1)
然後:s2 = s1 + X , 也有4個s2, 並轉為10進製表示。
最後合併:
SN = "s2" + "XXXX" + "s1"
4個解為:
SN_X1=KCTFREADYKXXXX1548396171915056368526513804948765619094392315806578461796159505215278288254
SN_X2=KCTFREADYKXXXX27495936700183671733408543181646240981077460232127048216208422649817010276214
SN_X3=KCTFREADYKXXXX30400107918474425978376949322697712945557532100693234514359350753673330338593
SN_X4=KCTFREADYKXXXX56347648446743041343258978699395188307540600017013704268771613898275062326553
題目取最小的解:
x < P/4,SN_X1 為有效答案。
解題思路
本題解題思路由看雪論壇ODPan提供:
這是一道數論高配題。整數要用大整數,方程要用模方程,模方程要用二次模方程,二次模方程要用二次模合數方程,求逆要選離散對數。
該題選用了mbedtls大數庫,可以對應著原始碼檢視分析。
程式的初步分析
作者一如既往的對話方塊程式,我們需要關心兩個程式。sub_403B00 輸入字元處理函式和sub_404270校驗函式。校驗函式做了抗F5小處理。將此處Nop掉即可F5分析。
.text:00404B1E pop ebp
輸入字元處理
簡單檢視了一下。合法字串使用“XXXX”進行分割,分為前後兩個部分,並轉化為string型別。
char__cdeclstrProcess(char*key, ctf10_Str *strRetKeyBefore, ctf10_Str *strRetKeyAfter)
{
char*pchar;// eax
unsigned__int64 XXXXlen;// ST04_8
char*index;// eax
char*index_1;// esi
ctf10_Str *strKeyBefore;// eax
ctf10_Str *strTemp;// eax
unsignedintkeyAfterLen;// ecx
_BYTE *pchar_keyAfter;// eax
intv11;// edi
char*pchar_keyAfter_1;// eax
charv13;// al
charv14;// al
charv15;// al
charresult;// al
charv17;// al
ctf10_Str strXXXX;// [esp+Ch] [ebp-3Ch]
ctf10_Str strKey;// [esp+1Ch] [ebp-2Ch]
ctf10_Str strKeyAfter;// [esp+2Ch] [ebp-1Ch]
intv21;// [esp+44h] [ebp-4h]
LOBYTE(strKey.field_0) = (_BYTE)key;
StrInitByFalg(&strKey,0);
strLoad(&strKey, key,strlen(key));
LOBYTE(strXXXX.field_0) = (_BYTE)key;
v21 =0;
StrInitByFalg(&strXXXX,0);
strLoadByInput(&strXXXX,0,4u,'X');
pchar = (char*)strXXXX.pchar;
LOBYTE(v21) =1;
if( !strXXXX.pchar )
pchar = (char*)&unk_4100FC;
HIDWORD(XXXXlen) = strXXXX.len;
LODWORD(XXXXlen) =0;
index = str_find(&strKey, pchar, XXXXlen);// find XXXX
index_1 = index;
if( index == (char*)-1)
gotoLABEL_39;
strKeyBefore = str_substr(&strKey, &strKeyAfter,0, (unsignedint)index);
LOBYTE(v21) =2;
strCpy(strRetKeyBefore, strKeyBefore,0,0xFFFFFFFF);
LOBYTE(v21) =1;
StrInitByFalg(&strKeyAfter,1);
strTemp = str_substr(&strKey, &strKeyAfter, (unsignedint)&index_1[strXXXX.len],0xFFFFFFFF);
LOBYTE(v21) =3;
strCpy(strRetKeyAfter, strTemp,0,0xFFFFFFFF);
LOBYTE(v21) =1;
StrInitByFalg(&strKeyAfter,1);
if( !strRetKeyBefore->len )
gotoLABEL_39;
keyAfterLen = strRetKeyAfter->len;
if( !keyAfterLen )
gotoLABEL_39;
pchar_keyAfter = (_BYTE *)strRetKeyAfter->pchar;
if( !pchar_keyAfter )
pchar_keyAfter = &unk_4100FC;
if( *pchar_keyAfter =='0')
{
LABEL_39:
LOBYTE(v21) =0;
StrInitByFalg(&strXXXX,1);
v21 =-1;
StrInitByFalg(&strKey,1);
return0;
}
v11 =0;
if( keyAfterLen >0)
{
while(1)
{
pchar_keyAfter_1 = (char*)strRetKeyAfter->pchar;
if( !pchar_keyAfter_1 )
pchar_keyAfter_1 = (char*)&unk_4100FC;
if( !isdigit(pchar_keyAfter_1[v11]) )// 數字
break;
if( (unsignedint)++v11 >= strRetKeyAfter->len )
gotoLABEL_14;
}
if( strXXXX.pchar )
{
v14 = *(_BYTE *)(strXXXX.pchar -1);
if( v14 && v14 !=-1)
*(_BYTE *)(strXXXX.pchar -1) = v14 -1;
else
strFree((LPVOID)(strXXXX.pchar -1));
}
strXXXX.pchar =0;
strXXXX.len =0;
strXXXX.field_C =0;
if( strKey.pchar )
{
v15 = *(_BYTE *)(strKey.pchar -1);
if( v15 && v15 !=-1)
{
*(_BYTE *)(strKey.pchar -1) = v15 -1;
result =0;
}
else
{
strFree((LPVOID)(strKey.pchar -1));
result =0;
}
returnresult;
}
return0;
}
LABEL_14:
if( strXXXX.pchar )// 全是數字的處理
{
v13 = *(_BYTE *)(strXXXX.pchar -1);
if( v13 && v13 !=-1)
*(_BYTE *)(strXXXX.pchar -1) = v13 -1;
else
strFree((LPVOID)(strXXXX.pchar -1));
}
strXXXX.pchar =0;
strXXXX.len =0;
strXXXX.field_C =0;
if( strKey.pchar )
{
v17 = *(_BYTE *)(strKey.pchar -1);
if( v17 && v17 !=-1)
{
*(_BYTE *)(strKey.pchar -1) = v17 -1;
return1;
}
strFree((LPVOID)(strKey.pchar -1));
}
return1;
}
校驗函式
該函式要滿足3個條件,才能返回正確結果。下面分別分析這三個條件。
函式初始化部分
大整數初始化
mbedtls_mpi_lset(&power0xff, v91);
BigInt_pow(&ret, &power0xff, v7);// 2^0xff
mbedtls_mpi_add_int(&power0xff, &ret, v8);// 2^0XFF - 0X13
mbedtls_mpi_sub_int(&powerSbu1, &power0xff,1);// /2^0XFF - 0X13 - 1
mbedtls_mpi_lset(&A, a4);
將輸入字串的兩部分轉化為大整數,我們假設a=keyBefore,b= keyAfter
mbedtls_mpi_copy(&keyBefore, &mytarget);
mbedtls_mpi_copy(&keyAfter, &srcNode);
第一個條件:4b < power0xff
mbedtls_mpi_add_mpi(&doubleAfter, &keyAfter, &keyAfter);
mbedtls_mpi_add_mpi(&node4b, &doubleAfter, &doubleAfter);
v12 = mbedtls_mpi_cmp_mpi(&node4b, &power0xff);// 4b < power0xff
第一個條件是個限制條件,4*b < 2^0xff – 0x13。
第二個條件:模方程
mbedtls_mpi_lset(&sum, v12 >=0);// v90 = 0
v13 =0;
v63 =0;
v14 = v50;
while( v13 < v14 )// v14= 6
{
mbedtls_mpi_sub_mpi(&afterSunBefor, &keyAfter, &keyBefore); r=b-a
powern(&desNode[v13], &afterSunBefor, *(&n + v13), &power0xff);// n=0,1,2,3,4,5
addNum(&v58, *(&num + v13), &desNode[v13], &sum, &power0xff);// a*num+v90 num = 3,0,1,0,0x40,0,1
mbedtls_mpi_copy(&sum, &v58);
v63 = ++v13;
}
mbedtls_mpi_sub_mpi(&a1a, &keyBefore, &sum);
這裡我們另r=b-a,迴圈6次的過程如下:
sum0 = r^0/N *3 =3
sum1 = r^1*0/N +sum0/N = 3
sum2 = r^2*1/N +sum1/N = (r^2+3)/N
sum3 = r^3*0/N +sum2/N = (r^2+3)/N
sum4 = r^4*0x40/N +sum3/N = 0X40r^4/N + (r^2+3)/N
sum5 = r^5*0/N +sum4
最後得到的方程:
(64r^4/N + (r^2 +3)/N)/n = a
這裡我們另x=r^2,這裡往回逆的時候要逆兩次。化簡後可得一個二次模方程:
64x^2 + x a = 0(mod N)
從方程可知,求出a即可反推x,r最後求得b。那麼我們繼續分析,看如何求a值。
第三個條件:離散對數
mbedtls_mpi_lset(&E,0);
maxTableData = getDataFormTable((char*)'X');// v15 = 0x19
maxTableData_1 = maxTableData;
maxTableData_2 = maxTableData;
index =0;
index_1 =0;
const0xA = *((_DWORD *)checkData +4);
buf =0;
memset(&v39,0,252u);
v40 =0;
v41 =0;
size = *((_DWORD *)checkData +1);
pcharend = (char*)(size + *(_DWORD *)checkData -1);
v36 = (char*)(size + *(_DWORD *)checkData -1);
pbuf = &buf;
v42 = &buf;
while( (unsignedint)pcharend >= *(_DWORD *)checkData )
{
*pbuf++ = *pcharend;
v42 = pbuf;
v36 = --pcharend;
}
buf += checkData[12];// 輸入字串前半部分keyBefore,最後一個字元+0xA
while( index <strlen(&buf) )
{
keyChar1 = (char*)*(&buf + index++);
index_1 = index;
numFromTableByKey = getDataFormTable(keyChar1);
numFromTableByKey_1 = numFromTableByKey;
v43 = numFromTableByKey;
if( numFromTableByKey >= maxTableData_1 )
{
errorFlag =1;
break;
}
mbedtls_mpi_mul_int(&E, &E, maxTableData_1);
mbedtls_mpi_add_int(&E, &E, numFromTableByKey_1);// 將keyBfore內容轉換為0x19進位制數
}
if( index <= const0xA && !errorFlag )// KEY 前半部分長度小於10
{
sushuCnt = createSuShuByRand(randNum, &buf2);// 產生素數列表和隨機檢測個數
randNum = sushuCnt;
for( j =0; ; ++j )// 米勒羅賓素性測試
{
v63 = j;
if( j >= sushuCnt || !*(&buf2 + j) )
break;
sub_4025A0(&ret_1, &E, *(&buf2 + j));
if( !ret_1 )
gotoLABEL_35;
}
get_gccd(&v58, &powerSbu1, &E);// gcd
if( node_getBitNum_0(&v58) <=1)
{
mbedtls_mpi_inv_mod(&D, &E, &powerSbu1);// D = E^-1 mod (N-1)
mbedtls_mpi_exp_mod(&final, &A, &D, &power0xff, &a5);// X = A^D mod N
mbedtls_mpi_sub_mpi(&v71, &nodeCheck, &final);
v25 = node_getData(&v71);
result3 = v25;
mbedtls_mpi_exp_mod(&a2, &nodeCheck, &E, &power0xff, &a5);// A = X^E mode N
mbedtls_mpi_sub_mpi(&v69, &a2, &A);
if( v25 )
result3 = node_getData(&v69);
}
程式碼幾個關鍵步驟說明:
1、 將keyBefore(輸入字串得前半部分)最後一位+0x0A;
2、 將keyBfore內容轉換為0x19進位制數,記作E;
3、 米勒羅賓素性測試,確保E為素數;
4、 E與(N-1)最大公約數為1
5、 檢測計算
D = E^-1 mod (N-1)
X = A^D mod N
A = X^E mode N
N=0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED
這裡我們已知A和X得四組資料,求D,求離散對數。利用作者dlp工具可以跑出D。這樣我們可以一路反推D->E->keyBefore->a,將a帶回二次模方程,這裡簡單提一下方程化簡過程:
64r^4 + r^2 + 3-0x4B435446524541445955 = 0 mod N
64x^2 + x + 3-0x4B435446524541445955 = 0 mod N
轉換為一般模方程:
x^2 = A mode M
A是奇數非素數,M是個合數 GCD(A,M)==1
其中
a = 64
b = 1
c =-0x4B435446524541445952
所以
A = b^2 - 4ac
M = 4aN
這樣經過兩次二次模方程求解可以解的r(b-a,b<4N。最終求得a,b。
aXXXXb= KCTFREADYKXXXX1548396171915056368526513804948765619094392315806578461796159505215278288254
▲
END
主辦方
看雪學院(www.kanxue.com)是一個專注於PC、移動、智慧裝置安全研究及逆向工程的開發者社群!建立於2000年,歷經19年的發展,受到業內的廣泛認同,在行業中樹立了令人尊敬的專業形象。平臺為會員提供安全知識的線上課程教學,同時為企業提供智慧裝置安全相關產品和服務。
合作伙伴
上海紐盾科技股份有限公司(www.newdon.net)成立於2009年,是一家以“網路安全”為主軸,以“科技源自生活,紐盾服務社會”為核心經營理念,以網路安全產品的研發、生產、銷售、售後服務與相關安全服務為一體的專業安全公司,致力於為數字化時代背景下的使用者提供安全產品、安全服務以及等級保護等安全解決方案。
天上真的掉餡餅啦!
面試跳槽沒有拿得出手的證照?
升職加薪能力不夠?
公司申請安全資質,但員工要求達不到?
一張CISP的證照,幫您解決全部問題。
預算不夠又想找靠譜的機構?
紐盾幫您解決全部問題,全新的上課機制,豐富的課程安排,超多大型專案供你累積經驗,透過率高達99%。
現報名還有優惠補貼,快來了解下吧。
10大議題正式公佈!第三屆看雪安全開發者峰會重磅來襲!
小手一戳,瞭解更多
相關文章
- 看雪.紐盾 KCTF 2019 Q3 | 第十題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q2 | 第九題點評及解題思路2019-07-04
- 看雪.紐盾 KCTF 2019 Q2 | 第一題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q2 | 第二題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q2 | 第三題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q2 | 第五題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q2 | 第七題點評及解題思路2019-07-02
- 看雪.紐盾 KCTF 2019 Q2 | 第八題點評及解題思路2019-07-03
- 看雪.紐盾 KCTF 2019 Q2 | 第六題點評及解題思路2019-07-01
- 看雪.紐盾 KCTF 2019 Q3 | 第十一題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第十二題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第十三題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第一題點評及解題思路2019-09-25
- 看雪.紐盾 KCTF 2019 Q3 | 第四題點評及解題思路2019-09-29
- 看雪.紐盾 KCTF 2019 Q3 | 第七題點評及解題思路2019-09-30
- 看雪.紐盾 KCTF 2019 Q3 | 第六題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第八題點評及解題思路2019-10-08
- 看雪.紐盾 KCTF 2019 Q3 | 第九題點評及解題思路2019-10-08
- 2019KCTF 晉級賽Q1 | 第十題點評及解題思路2019-04-08
- 看雪.WiFi萬能鑰匙 CTF 2017第十題 點評及解題思路2017-06-28WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第十三題 點評及解題思路2017-06-28WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第十一題 點評及解題思路2017-06-28WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第十四題 點評及解題思路2017-06-30WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第十五題 點評及解題思路2017-08-10WiFi
- 看雪·深信服 2021 KCTF 春季賽 | 第十題設計思路及解析2021-05-31
- 看雪·眾安 2021 KCTF 秋季賽 | 第十題設計思路及解析2021-12-16
- 看雪.WiFi萬能鑰匙 CTF 2017第十二 點評及解題思路2017-06-28WiFi
- 看雪·眾安 2021 KCTF 秋季賽 | 第十一題設計思路及解析2021-12-15
- 2019 KCTF 晉級賽Q1 | 第三題點評及解題思路2019-03-28
- 2020 KCTF秋季賽 | 第一題點評及解題思路2020-11-20
- 2020 KCTF秋季賽 | 第四題點評及解題思路2020-11-24
- 2019KCTF 晉級賽Q1 | 第九題點評及解題思路2019-04-04
- 看雪.WiFi萬能鑰匙 CTF 2017第五題 點評及解題思路2017-06-28WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第四題 點評及解題思路2017-06-29WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第三題 點評及解題思路2017-06-29WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第七題 點評及解題思路2017-06-22WiFi
- 看雪.WiFi萬能鑰匙 CTF 2017第八題 點評及解題思路2017-06-22WiFi
- 看雪·深信服 2021 KCTF 春季賽 | 第七題設計思路及解析2021-05-25