GFCTF2021復盤


比賽打到中午就溜溜球去新生賽幫忙了,所以試圖復盤此次比賽部分題目

因個人水平有限,復現的題目僅包括(每題提供附件):

  • misc全部題目(重生之我在A國當間諜,pikapikapika,雙擊開始冒險)
  • re部分題目(Wordy,easy_low)
    逆向剩余的部分題目有個師傅在52上寫了,我舔!https://www.52pojie.cn/thread-1551240-1-1.html

Misc

重生之我在A國當間諜

鏈接:https://pan.baidu.com/s/1pkAtfcm5MI4hSBFFu-8yHQ
提取碼:eqyq

拿到題目后 winhex 打開

看到 ASCII 部分很像 hex 值,於是復制出來再以 hex 的形式保存到新的文件

看到有串長得很像 base64 的字符串

base64decode 一下,得到解壓密碼:[1e4rl0/e

但是賽后看大佬 wp 得知這其實是 PDU 編碼,一句一句解密就可以,網址:http://www.sendsms.cn/pdu/

倒數第二句解密出來是:真讓人無語。我把密碼告訴你,記住,這個密碼不要告訴任何人。WzFlNHJsMFwvZQ==

算是非預期了吧,這題的分我本不配拿QAQ

言歸正傳,繼續往下做題,用密碼解開壓縮包以后,看到是一張撕毀了的二維碼,本來想着截圖成一塊一塊拼到一起,結果顯然是不行的,啥也掃不出來。於是扔給會 ps 的咸魚舍友,才終於拼出了flag

GFCTF{ctf_Ha0_NaN_aaAaaaAaaaaAaaaaaAaa}

pikapikapika

鏈接:https://pan.baidu.com/s/1gcQxhrQvPRFMhQhEBTiPLA
提取碼:lze7

拿到題目 binwalk 發現有個壓縮包

分離出來后解壓提示需要密碼,看一眼皮卡丘

按照這個順序組合出解壓密碼為:I_want_a_p1ka!

解壓后得到 flag.wav,用 Audacity 打開看看,發現一共 2 種頻率,不難想到低位對應 0,高位對應 1

不會寫腳本,抱着僥幸心理想會不會有用信息就一部分,往后就都是重復的,手擼了一會后發現其實並不,於是就心安理得擺爛了(叉腰

賽后看了大佬的 wp,才得以了解此題

有一點注意的是跑腳本前需要處理一下 wav 文件,只保留其中的 data 部分,如下圖所示

腳本如下(來源:套神)

f = open('flag.wav','rb').read()
flag = ''
for i in range(len(f)//2):
    if(f[i*2:i*2+2] == b'\x98:'):
        flag += '0'
    else:
        flag += '1'
s = ''
rflag = ''
for i in flag:
    s+=i
    if len(s)==8:
        rflag += chr(int(s,2))
        s=''
print(rflag)

得到一串 base64,放到 cyberchef 解密一下保存為 png,發現很明顯改了圖片的高,改高一點就可以發現 flag 啦

GFCTF{fe1a-17f7-a7f6-1f8f534e-ef3974-c049c5}

雙擊開始冒險

鏈接:https://pan.baidu.com/s/1Q4GrX8XGgVeQkt0JugJcSw
提取碼:cgai

第一步爆破密碼,四位數,上 AZPR

解壓后來到第二層,打開 hint 拉到最右邊,中間的地方有句話

搜索對應 QQ 號,看到簽名(因為復現時時間已經是賽后兩天了,所以此人只保留了簽名,比賽時名字也是base64,雖然我強調這個好像也沒什么必要),WW91IGxvdmUgbWUsIEkgbG92ZSB5b3U=

base64decode 得到:You love me, I love you,解壓壓縮包,來到第三層

看到給出了一個 usb 鼠標流量,此前只接觸過鍵盤流量,上網搜了幾篇文章對着弄但不知道為啥啥也提取不出來,於是又順理成章擺爛了

賽后看別人 wp,發現大家都能提取出來,整個被大疑惑到,但我肯定我確實是提取不出來,又通過一中午的不懈嘗試,終於發現雖然在 kali 里提取了個寂寞但是在 windows 下卻可以提取出來......原因不明,但覺得自己血虧

tshark -r usb.pcapng -T fields -e usb.capdata > usbdata.txt

提取后發現有很多空行,想着用 sed 一步到位然而發現又什么都提取不出來,只得手動腳本加工來把空行去掉

file1 = open('usbdata.txt', 'r', encoding='utf-8') 
file2 = open('usbdat.txt', 'w', encoding='utf-8') 

for line in file1.readlines():    
    if line == '\n':        
       line = line.strip("\n")       
    file2.write(line) 
file1.close()
file2.close()

得到了一串 16 位的流量數據,提取第 0 2 4 6 字節來畫圖(說明:接下來的腳本來源均為套神博客)

f = open('usbdat.txt','r').readlines()
f1 = open('usb.txt','w')
for i in range(len(f)):
    f[i] = f[i].split(':')
for i in range(len(f)):
    tmp = ''
    for j in range(4):
        tmp += f[i][j*2]+':'
    f1.write(tmp)
    f1.write('\n')

接下來轉換成坐標(y坐標需要加個負號)

nums = []
keys = open('usb.txt','r')
result=open('result.txt','w')
posx = 0
posy = 0
for line in keys:
    if len(line) != 13:
         continue
    x = int(line[3:5],16)
    y = int(line[6:8],16)
    if x > 127 :
        x -= 256
    if y >127 :
        y -=256
    posx += x
    posy += y
    btn_flag = int(line[0:2],16)  # 1 for left , 2 for right , 0 for nothing
    if btn_flag == 1:
        result.write(str(posx)+' '+str(-posy)+'\n')
keys.close()
result.close()

用 gnuplot 畫圖得到:

7724774CTF,解壓得到

winhex 打開,flag 就在結尾

GFCTF{this_is_rea1_fllllll11ag}

RE

Wordy

鏈接:https://pan.baidu.com/s/1B7HFDUk1PC_d3WTYW9X6mw
提取碼:mt1t

IDA 打開,看到 hex 窗口,很明顯可以看到一串可疑字符

讀一下,hello world! There are moments in...

bb了賊長的一段,往下拉一段距離就可以看到 flag

GFCTF{u_are2wordy}

easy_low

鏈接:https://pan.baidu.com/s/1bNQ1MDZZ7ucqhPR1x0rCYg
提取碼:p4w8

jadx 打開,定位到 MainActivity

簡單分析一下,看到點擊事件 onClick,先看第一部分

這一部分輸入兩個字符串,用戶名和密碼,並且可以得知二者長度均為 16,然后進入下一部分

用戶名先通過 encode 函數進行加密,查看一下 encode

函數傳入輸入的用戶名也就是 str,以及一個已知數組,通過 for 循環進行兩次變換,最后變換后的結果與其原值一致,所以可以據此寫出腳本爆破出用戶名

#include <bits/stdc++.h>
using namespace std;
int num_list[] = {23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 32, 32};
string user_name;
inline bool check(int a, int pos) {
  int num = ((a + num_list[pos]) % 61) * 2 - pos;
  if (num == a) return true;
  else return false;
}
int main() {
  for (int i = 0; i < 16; i++)
    for (int j = 0; j < 125; j++)
      if (check(j, i)) user_name += (char)j;
  cout << user_name << endl;
  return 0;
}

得到用戶名為:LOHILMNMLKHILKHI

然后繼續看獲取密碼的部分

對用戶名每一位異或 34,取前 10 位存入 str,str 再與 '_' 以及 bArr 拼接,然后將 str 與用戶輸入的密碼作比較,因此可以逆向出密碼

#include <bits/stdc++.h>
using namespace std;
int Llist[] = {64, 48, 48, 49, 49};
int num_list[] = {23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 32, 32};
int num[] = {0xF2, 0xE, 0x95, 0x5D, 0xDE, 0xA2, 0xCC, 0x86, 0xF4, 0xBB, 0x39, 0xC0, 2, 0x81, 0x94, 0xC5, 0x9C, 0x5E, 0xD5, 0xAE, 0x77, 0x43, 0xF1, 0x89};
string user_name, user_pass;
inline bool check(int a, int pos) {
  int num = ((a + num_list[pos]) % 61) * 2 - pos;
  if (num == a) return true;
  else return false;
}
int main() {
  for (int i = 0; i < 16; i++)
  	for (int j = 0; j < 125; j++)
  	  if (check(j, i)) user_name += (char)j;
  for (int i = 0; i < 16; i++) 
    user_name[i] = (char)((int)user_name[i] ^ 34);
  for (int i = 0; i < 10; i++) user_pass += user_name[i];
  user_pass += '_';
  for (int i = 0; i < 5; i++) user_pass += Llist[i];
  cout << user_pass;
  return 0;
}

得到密碼為:nmjknoloni_@0011

接下來可以發現該活動通過 Intent 將密碼傳進了 o0 這個活動里面,o0 如下

o0 類把密碼又傳給了 b 類,查看 b

b 類調用了一個 f 類的 oho 方法,查看 f

oho 在 native 層,總之,它就是最終的加密⽅法。它將我們的密碼,用戶名以及在第三個界⾯輸入的內容進行了加密並做比較,返回值 boolean 正確則輸出 Congratulations...

反編譯 apk,把 so 文件拖入 IDA,找到 oho

這個函數先對傳入的參數的長度進行比較,得知 flag 的長度應當為 24

然后看循環部分,通過分析可以發現是將密碼每次 2 位傳給 src,用戶名則是先倒置再每次 2 位接在 src 后面,然后再與用戶第三個輸入的內容拼接后傳入 encode 進行最終的加密,查看 encode

看不懂嗚嗚嗚,菜雞落淚,找了出題師傅要的腳本,才勉強看懂了

#include <bits/stdc++.h>
using namespace std;
int main() {
  char key1[]={"nNjLnHlL"};
  int count=1;
  int key[7];//nNjLnHlL
  for (int i = 0; i < 6; ++i) {
    key[i] = key1[count];
    count++;
  }
  unsigned int ks[6]={0x5d950ef2,0x86cca2de,0xc039bbf4,0xc5948102,0xaed55e9c,0x89f14377};
  unsigned int k=0,bk=0;
  unsigned int p[4];
  for(int i=5;i>=0;i--)
	if(i>0) ks[i]^=ks[i-1];
  for(int i=0;i<24;i+=4){
	k=ks[i/4];
	k=(1<<key[i/4])^k;
	k=((k>>16)) | ((~(k<<16))&0xffff0000);  //這一句還有些疑問,求會的師傅講講QAQ,小的定感激不盡
	k=((k<<key[i/4])) | (k>>(32-key[i/4]));
	for(int j=0; j<4; j++) printf("%c", *((char*)&k+3-j));
  }
  return 0;
}

解出:WelCOme_To_mAkaBakA!BrO!,包裹上 GFCTF{} 得到 flag

GFCTF{WelCOme_To_mAkaBakA!BrO!}

此次比賽感悟:大抵是因為題目相對簡單的緣故,最起碼在做題的時候能略微有些思路了,然而也暴露出了許多問題,例如腳本屁也不會寫。總而言之,這次比賽是一個令我這種啥也不會的萌新參與感很高的一次比賽,雖然做出來的題不多,但每個題都能有些思路並且做幾步。雖說給自己的方向的定位是逆向,但是在比賽中還是雜項做的更多一些,說到底還是人太菜了,尤其是安卓逆向最后那個 native 層的加密,不看師傅的解題腳本根本就不知道在說什么,從今往后還是要多刷題,還差得遠啊qwq


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM