今天是很特別的一天呢,七月一日,一週的第一天,一月的第一天,下半年第一天,建黨98週年,香港迴歸的22週年。
小夥伴們週末愉快玩耍時,有沒有看我們公佈的KCTF英雄榜單呢?你是否榜上有名呢?
一路走來,我們接到神秘來信,喚醒沉睡的敦煌,破解金字塔的詛咒,開啟神秘的達芬奇密碼,昨天我們一起探索了叢林的秘密,今天讓我們一起來解析第六題,尋找消失的島嶼~
題目簡介
題目背景:
走出森林,是潔白的沙灘,湛藍的海水,和曬太陽的螃蟹。遠處影影綽綽的有幾座小島。突然,濃墨色的黑煙正在慢慢的向這邊的天空渲染。外星人的戰艦在黑雲中若隱若現,並越發密集。遠方的島嶼正在慢慢沉入海水之中,腳下的沙灘也慢慢的被海水覆蓋,海水正在吞噬這些島嶼,留給我們的時間不多了。
在這些眾多的島嶼之中,究竟哪一個藏了寶石?你又該怎樣前往這些島嶼呢?
本題共有2170人圍觀,最終有153支團隊攻破成功。這道題是除第一題外,攻破人數最多的一道題,相對來說,這道題還是比較簡單的。
攻破此題的戰隊排名一覽:
接下來我們來對題目進行解析,破解其中的奧秘。
看雪評委crownless點評
本題考查了修改過編碼table的base64演算法,重點在於單個字元的變換強度。真實的編碼table從頭到尾不會在記憶體中顯示。所以攻擊者需要先將斷點設定在charEncrypt處,找出編碼的變換規則,然後找到修改過後的編碼table,根據變換規則推匯出真正的編碼table。
出題團隊簡介
本題出題戰隊 iret :
iret 團隊簡介:某安全公司實習生,目前正在學習逆向和木馬分析,希望能從各位大佬身上學習並提升自己。
設計思路
該題目為base64魔改的CrackMe。
首先定義了一個自定義的base64編碼table:
#defineTABLE1"tuvwxTUlmnopqrs7YZabcdefghij8yz0123456VWXkABCDEFGHIJKLMNOPQRS9+/"
然後定義了一個單個字元加密的方法:
staticcharcharEncrypt(intdata)
{
char*table = TABLE1;
data = table[data];
if(data>=65&& data<=90)
{
data = (155-data) ;
return(char)data;
}
if(data>=97&&data<=122)
{
data = (data-64);
return(char)data;
}
if(data>=48&&data<=57)
{
data = (data +50) ;
return(char)data;
}
if(data==43)
{
data =119;
return(char)data;
}
if(data==47)
data =121;
return(char)data;
}
接下來使用c語言實現了base64編碼,不僅使用修改後的編碼table,還會在賦值的時候呼叫單個字元加密方法將字元加密後賦值。
破解思路:
本題的重點在於單個字元的變換強度。真實的編碼table從頭到尾不會在記憶體中顯示。所以攻擊者需要先將斷點設定在charEncrypt處,找出編碼的變換規則,然後找到修改過後的編碼table,根據變換規則推匯出真正的編碼table。
完整程式碼:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<inttypes.h>
#defineTABLE1"tuvwxTUlmnopqrs7YZabcdefghij8yz0123456VWXkABCDEFGHIJKLMNOPQRS9+/"
/*base64編/解碼用的基礎字符集*/
staticcharcharEncrypt(intdata)
{
char*table = TABLE1;
data = table[data];
if(data>=65&& data<=90)
{
data = (155-data) ;
return(char)data;
}
if(data>=97&&data<=122)
{
data = (data-64);
return(char)data;
}
if(data>=48&&data<=57)
{
data = (data +50) ;
return(char)data;
}
if(data==43)
{
data =119;
return(char)data;
}
if(data==47)
data =121;
return(char)data;
}
staticintbase64_encode(constuint8_t*bindata,char*base64,intbinlength)
{
inti, j;
uint8_tcurrent;
for( i =0, j =0; i < binlength ; i +=3) {
current = (bindata[i] >>2) ;
current &= (uint8_t)0x3F;
base64[j++] = charEncrypt((int)current);
current = ( (uint8_t)(bindata[i] <<4) ) & ( (uint8_t)0x30) ;
if( i +1>= binlength ) {
base64[j++] = charEncrypt((int)current);
base64[j++] ='=';
base64[j++] ='=';
break;
}
current |= ( (uint8_t)(bindata[i+1] >>4) ) & ( (uint8_t)0x0F);
base64[j++] = charEncrypt((int)current);
current = ( (uint8_t)(bindata[i+1] <<2) ) & ( (uint8_t)0x3C) ;
if( i +2>= binlength ) {
base64[j++] = charEncrypt((int)current);
base64[j++] ='=';
break;
}
current |= ( (uint8_t)(bindata[i+2] >>6) ) & ( (uint8_t)0x03);
base64[j++] = charEncrypt((int)current);
current = ( (uint8_t)bindata[i+2] ) & ( (uint8_t)0x3F) ;
base64[j++] = charEncrypt((int)current);
}
base64[j] ='\0';
returnj;
}
intmain(intargc,char**argv)
{
charstr1[55];
printf("please enter Serial:");
scanf(" %s",str1);
if(strlen(str1)>=50)
{
printf("error\n");
exit;
}
char*base64_str =calloc(1,1024);
base64_encode(str1, base64_str,strlen(str1));
char*str ="!NGV%,$h1f4S3%2P(hkQ94==";
if(!strcmp(str,base64_str))
{
printf("Success\n");
}else{
printf("Please Try Again\n");
}
free(base64_str);
system("pause");
return0;
}
解題思路
本題解題思路由看雪論壇qwertyaa提供:
可以看到這個程式主要是 BASE64 的變體,它裡面的 charEncrypt 如下:
charfrom[]="tuvwxTUlmnopqrs7YZabcdefghij8yz0123456VWXkABCDEFGHIJKLMNOPQRS9+/";
charcharEncrypt(chardata)
{
chardataa;
dataa =from[data];
if( dataa >'@'&& dataa <='Z')
return-101- dataa;
if( dataa >'`'&& dataa <='z')
returndataa -64;
if( dataa >'/'&& dataa <='9')
returndataa +50;
if( dataa =='+')
return'w';
if( dataa =='/')
dataa ='y';
returndataa;
}
而普通的 BASE64 的 charEncrypt 如下:
charreb[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
charcharEncrypt(chardata)
{
chardataa;
dataa = reb[data];
returndataa;
}
兩個 charEncrypt 都是置換,對每個字元求第一個置換的逆置換後進行第二個置換的結果即可,程式碼如下:
#include<bits/stdc++.h>
usingnamespacestd;
charreb[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
charfrom[]="tuvwxTUlmnopqrs7YZabcdefghij8yz0123456VWXkABCDEFGHIJKLMNOPQRS9+/";
charresult[]="!NGV%,$h1f4S3%2P(hkQ94==";
charcharEncrypt(chardata)
{
chardataa;
dataa = from[data];
if( dataa >'@'&& dataa <='Z')
return-101- dataa;
if( dataa >'`'&& dataa <='z')
returndataa -64;
if( dataa >'/'&& dataa <='9')
returndataa +50;
if( dataa =='+')
return'w';
if( dataa =='/')
dataa ='y';
returndataa;
}
charre[256];
intmain(){
for(inti=0;i<strlen(reb);i++){
re[charEncrypt(i)]=i;
}
intlen=strlen(result);
for(inti=0;i<len;i++)if(result[i]!='='){
result[i]=reb[re[result[i]]];
}
puts(result);
}
將結果用 javascript 的 atob 函式解碼得FLAG: KanXue2019ctf_st。
▲
END
1、【英雄榜單】看雪.紐盾 KCTF 晉級賽Q2 排行榜出爐!
2、看雪.紐盾 KCTF 2019 Q2 | 第一題點評及解題思路
3、看雪.紐盾 KCTF 2019 Q2 | 第二題點評及解題思路
4、看雪.紐盾 KCTF 2019 Q2 | 第三題點評及解題思路
5、看雪.紐盾 KCTF 2019 Q2 | 第四題點評及解題思路
6、看雪.紐盾 KCTF 2019 Q2 | 第五題點評及解題思路
主辦方
看雪學院(www.kanxue.com)是一個專注於PC、移動、智慧裝置安全研究及逆向工程的開發者社群!建立於2000年,歷經19年的發展,受到業內的廣泛認同,在行業中樹立了令人尊敬的專業形象。平臺為會員提供安全知識的線上課程教學,同時為企業提供智慧裝置安全相關產品和服務。
合作伙伴
上海紐盾科技股份有限公司(www.newdon.net)成立於2009年,是一家以“網路安全”為主軸,以“科技源自生活,紐盾服務社會”為核心經營理念,以網路安全產品的研發、生產、銷售、售後服務與相關安全服務為一體的專業安全公司,致力於為數字化時代背景下的使用者提供安全產品、安全服務以及等級保護等安全解決方案。
小手一戳,瞭解更多