# Final CTF :::success 網址: [final.nisra.net](https://final.nisra.net) token: NISRA{W3lc0M3_2_F1na1_CTF} CTF 持續日期: 2024/8/29 ~ 2024/9/6 ::: 題目表 --- - MISC - [0x0](#0x0---sicc) - [0x1](#0x1---sicc) - [0x2](#0x2---sicc) - [0x3](#0x3---sicc) - [0x4](#0x4---sicc) - [0x5](#0x5---sicc) - [0x6](#0x6---sicc) - [0x7](#0x7---hA) - [0x8](#0x8---hA) - [0x9](#0x9---hA) - Pwn - [HowLong](#HowLong---sicc) - [moneyANDskill](#moneyANDskill---sicc) - [moneyANDskill_rev](#moneyANDskill_rev---sicc) - Crypto - [bababase64](#bababase64---sicc) - [ROT](#ROT---sicc) - [Password_good](#Password_good---sicc) - [維吉尼亞密碼+社交工程](#維吉尼亞密碼+社交工程---sicc) - OS - [/?/?/flag.txt](#/?/?/flag.txt---sicc) - Web - [ψ(`∇´)ψ](#ψ(`∇´)ψ---101) - [Hello](#Hello---101) - [Pick cat!](#Pick cat!---sicc) - [Invisible](#Invisible---101) - [GETGETGET](#GETGETGET---101) - [🍪](#🍪---101) ## MISC ### 0x0 - sicc >Flag 在 0x0.txt 中 <!-- NISRA{I_4CC3Pt_tH3_CH4LL3nG3_4nD_I_4m_r34dY} --> ### 0x1 - sicc >1. 看到標頭是 `89 50 4E 47 0D 0A 1A 0A`(PNG 格式),但結尾是 `FF D9`(jpg 格式),所以選擇將標頭改成 `FF D8 FF E0 00 10 4A 46 49 46` ![image](https://hackmd.io/_uploads/HJ6wl-LnR.png) >2. 然後將圖片高度改為 `04 F4` 就能夠找到 flag 了 <!-- NISRA{JP3G_15_FuN} --> ### 0x2 - sicc >1. 看到結束的地方有一串 base64 編碼的字串 >![image](https://hackmd.io/_uploads/H1Mv7-8nC.png) >2. 拿去 Cyberchef 解碼就能得到解答 <!-- NISRA{w0w_Y0u_F1nD_Th3_C0mm3nT} --> ### 0x3 - sicc >1. 將兩張圖下載下來後拿去 Stegsolve 進行 Analyse -> Image Combiner 進行分析, XOR 的情況下會得到一張 QR code >2. 拿去線上解析(cyberchef 也可以) 或是拿手機掃就能夠得到 flag <!-- NISRA{Y0u_G0t_m3} --> ### 0x4 - sicc >在 0x3_B.png 中,發現 R G B 的 0 bit 左上角都有不明的黑色 >利用 analyse -> Data Extract ,選擇 LSB 與 RGB 是 0 <!-- NISRA{10v3_10v3_NISRA_F03v3R} --> ### 0x5 - sicc >1. 根據 `encrypt3.py` 我們知道它是由 png 跟一個 key 經過 xor 生成 crack.png >2. png 的標頭組成是固定的,所以我們將隨便一張 png 作為 flag.png 與 crack.png 進行 xor 就能夠得到 flag >原理: A~.png~ xor B~.txt~ = C~.png~ >B~.txt~ = A~.png~ xor C~.png~ (兩邊同時 xor A~.png~) :::spoiler 自寫 pyhton ```python= # XOR 函式 def xor(bt1, bt2): res = [0]*16 for i in range(len(res)): q = bt1[i] d = bt2[i] k = q ^ d res[i] = k return bytes(res) def add_pad(msg): l = 16 - len(msg) % 16 msg += bytes([l] * l) return msg # 讀取 ox3_B.png 作為 A.png with open('0x3_B.png', 'rb') as f: data = f.read() data = add_pad(data) # 讀取 carck.png 作為 C.png with open('crack.png', 'rb') as f: key = f.read() enc_data = bytearray() for i in range(0, len(data), 16): enc = xor(data[i:i+16], key[:16]) enc_data.extend(enc) # 輸出 a.txt = flag with open('a.txt', 'wb') as f: f.write(enc_data) ``` ::: <!-- NISRA{3Nl1GHt3N} --> ### 0x6 - sicc >1. 解題辦法與上題類似,只需要將腳本修改一下 :::spoiler 改過的腳本 ```python= def xor(bt1, bt2): res = [0]*16 for i in range(len(res)): q = bt1[i] d = bt2[i] k = q ^ d res[i] = k return bytes(res) def add_pad(msg): l = 16 - len(msg) % 16 msg += bytes([l] * l) return msg with open('crack.png', 'rb') as f: data = f.read() data = add_pad(data) with open('a.txt', 'rb') as f: key = f.read() enc_data = bytearray() for i in range(0, len(data), 16): enc = xor(data[i:i+16], key[:16]) enc_data.extend(enc) with open('flag.png', 'wb') as f: f.write(enc_data) ``` ::: <!-- NISRA{s0_Y0u_r34llY_Kn0w_wH4t_X0r_15} --> ### 0x7 - hA > 我們只需要知道RGB各個資訊的最小有效位就可以了,但是嵌入的順序是隨機的...... > 所幸我們有sequence.txt,只需要把其中的兩個數字當作x,y值, > 就可以按照sequence的順序得到flag了 :::spoiler 自寫python ```python= from PIL import Image def load_sequence_from_file(filename): sequence = [] with open(filename, "r") as f: for line in f: w, h = map(int, line.strip().split(",")) sequence.append((w, h)) return sequence def lsbDecodeWithRandom(l, infile, outfile, sequence_file): img = Image.open(infile) sequence = load_sequence_from_file(sequence_file) f = open(outfile, 'wb') abyte = 0 lenth = l * 8 count = 0 for w, h in sequence: if count >= lenth: break pixel = img.getpixel((w, h)) for i in range(3): abyte = (abyte << 1) + (int(pixel[i]) & 1) count += 1 if count % 8 == 0: f.write(bytes([abyte])) abyte = 0 if count >= lenth: break f.close() input = '0x7.png' flag = 'flag.txt' sequenceFile = 'sequence.txt' lsbDecodeWithRandom(50,input,flag,sequenceFile) ``` ::: <!-- NISRA{r4nD0m_L5B_53nP41_sk} --> ### 0x8 - hA > LSB可以寫在音訊中,音訊一般會用16bits去儲存聲音,但我們只需要最小有效位就可以了 :::spoiler 自寫python ```python= import wave def extract_message_from_audio(l, infile, outfile): with wave.open(infile, 'rb') as audio: frame_bytes = bytearray(audio.readframes(audio.getnframes())) extracted_bits = [str(frame_bytes[i] & 1) for i in range(l * 8)] extracted_message = ''.join(chr(int(''.join(extracted_bits[i:i+8]), 2)) for i in range(0, len(extracted_bits), 8)) with open(outfile, 'w') as f: f.write(extracted_message) input = '0x8.wav' flag = 'flag.txt' extract_message_from_audio(50,input,flag) ``` ::: <!-- NISRA{L5b_w1Th_Mu51c_15_FuN} --> ### 0x9 - hA > 與上題的題目相似,但是一樣要用sequence.txt去解決嵌入順序隨機的問題 :::spoiler 自寫python ```python= import wave def load_sequence_from_file(filename): sequence = [] with open(filename, "r") as f: for line in f: index = int(line.strip()) sequence.append(index) return sequence def lsbDecodeWithRandom(l, infile, outfile, sequence_file): with wave.open(infile, 'rb') as audio: frame_bytes = bytearray(audio.readframes(audio.getnframes())) sequence = load_sequence_from_file(sequence_file) message_length = l * 8 extracted_bits = [] count = 0 for index in sequence: if count >= message_length: break extracted_bits.append(str(frame_bytes[index] & 1)) count += 1 extracted_message = ''.join(chr(int(''.join(extracted_bits[i:i+8]), 2)) for i in range(0, len(extracted_bits), 8)) with open(outfile, "w") as f: f.write(extracted_message) input = '0x9.wav' output = 'flag.txt' sequence = 'sequence.txt' lsbDecodeWithRandom(50,input,output,sequence) ``` ::: <!-- NISRA{r4nD0m_L5B_w1Th_Mu51c_15_50_c00L} --> ## Pwn ### HowLong - sicc >1. 分析 check_status() 發現他對輸入沒有限制,而輸入的 buffer 最大格數為 20,可以對其進行 overflow 去覆蓋 status,使其變為 'Y' >2. nc 連上之後,選擇 2 進行輸入,輸入一定數量的 Y 就能夠覆蓋 ![image](https://hackmd.io/_uploads/HJ5awrUhR.png) >3. 這時候輸入 1 隨便買一個東西就會噴出 flag <!-- NISRA{WhY_u_c4n_kn0W_L3N_15_32??!!} --> ### moneyANDskill - sicc >1. 同上題,只是輸入長度要長一點 ![image](https://hackmd.io/_uploads/B1V0OSLn0.png) >2. 發現錢不夠,想辦法讓錢變多,分析 check_funds 後發現可以藉由輸入負數增加資金 ![image](https://hackmd.io/_uploads/SyYxtrUhC.png) >3.最後再去買下 flag <!-- NISRA{U_h4V3_MOn3y_4nD_5k1ll!!} --> ### moneyANDskill_rev - sicc >1. 同上題,只是輸入的時候發現輸太長會直接跳出去,所以要控制好大小 ![image](https://hackmd.io/_uploads/H1V7nB82C.png) <!-- 因為 sicc 在上面那題偷偷有幫你們把輸入過濾掉,所以只要輸入超過大小即可 --> >2. 輸入不能輸入負數了,發現只要輸入超過 int 大小的就有一樣的效果 ![image](https://hackmd.io/_uploads/BkpR3SUnR.png) >3. 最後進行購買 <!-- NISRA{FRu17_M4S73r_Y0u_4r3_7H3_bes7_hacker_1n_7h3_SH0P} --> ## Crypto ### bababase64 - sicc - 一堆 base 64 encode 的句子 - 根據題目的提示可以知道經過了三次 - 解題工具 - [cyberchef](https://gchq.github.io/CyberChef/) > 在 Recipe 之中塞入 3 個 From Base 64 即可得到解答 <!-- NISRA{B@_bA_B@s364!!!} --> ### ROT - sicc - 根據題目知道句子是經過 ROT 轉換的 - 解題工具 - [cyberchef](https://gchq.github.io/CyberChef/) > 在 Recipe 中放入 ROT 13 Brute Force 即可進行暴力硬解 <!-- NISRA{R0T_TT_:DD_XDD} --> ### Password_good - sicc - Password: 密碼, good: 棒 -> 密碼棒 - 解題工具 - [Scytale Cipher](https://www.a.tools/Tool.php?Id=266) - 根據不同的解題網站可能解出來的答案會有大小寫 > 已知文句長度為 24 ,所以我們 Decrypt 先測試 6 ,發現即為答案 <!-- NISRA{finalctfisgoodanduserful} --> <!-- 對 user 是我打錯 但也是為了補字 --> ### 維吉尼亞密碼+社交工程 - sicc - 根據題目可以知道是維吉尼亞密碼 - 密鑰根據 hint 是在 sicc 身上娃娃的名字 <!-- sicc 為了這隻娃娃花費了很多錢錢還有時間(找了很久),它也是 sicc 去日本的旅伴 --> - 解題工具 - [cyberchef](https://gchq.github.io/CyberChef/) > Recipe 中拉取 Vigenère Decode > 再從 sicc 身上找到 key = Sullyoon > 最後進行 Decode 就能得到結果 <!-- NISRA{WherEEstHEKeEYEEEEE} --> ## OS ### /?/?/flag.txt - sicc - 根據題目可以知道 flag.txt 藏在根目錄中其中一個資料中 > 在 srv 資料夾中發現一個 Thereisnoflag 資料夾 > `sudo su root` 變更為 root 權限進入 > `cat flag.txt` 即可得到 flag <!-- NISRA{L1unx_1S_@_go0D_T0OL} --> ## Web ### ψ(`∇´)ψ - 101 1. 點開題目連結,然後打開F12檢查該網頁的原始碼有沒有線索 ![image](https://hackmd.io/_uploads/SyiKDfRj0.png) 2. 看到提示說跟"機器人"有關,聯想到 <b>robots.txt</b> 3. robots.txt會放在網頁的根目錄之下,用找尋檔案路徑的概念,修改網址找到該網頁的robots.txt 4. 將網址修改成```http://chall2.nisra.net:41032/robots.txt```之後,看到其內容如下 ![image](https://hackmd.io/_uploads/r1Oc_f0s0.png) 5. 將網址修改成```http://chall2.nisra.net:41032/secret.html```,看到寫著flag的連結 ![image](https://hackmd.io/_uploads/SyOHo9k3R.png) 6. 點進去就能看到正在瘋狂旋轉的flag (抓到flag的方法: 可以開F12複製,或是全選複製網頁文字之類的) ### Hello - 101 1. 在輸入框中輸入東西並送出,可以看到下方出現 Hello, XXX 2. 打開 F12,可以發現表單是用 GET 方式傳送,所以參數會出現在網址列 3. 輸入 HTML 標籤,如 `<h1>123</h1>` 會發現標籤會以標題形式呈現在網頁上 4. 點擊 F12 的 Source,看到 hello.js 檔案,發現他使用 `.innerHTML`,所以 HTML 標籤可以直接被貼進 HTML 檔中 5. 在看到 alert.js 檔案中複寫了 alert,會彈出奇怪的 text,很有可能是 flag 6. 但因為 `.innerHTML` 會擋 <script\> 標籤,所以要嘗試其他種方式把 alert() 塞進去,可以透過 `onload`、`onclick` 或是 `onerror` 7. 我們可以在輸入框或是網址列中輸入 `<img src onerror="alert();">`,因為圖片路徑是空的,所以會導致讀取錯誤,觸發 onerror 裡面的 alert,因此得到 flag ### Pick cat! - sicc 1. 點開來發現中間圖片,點選他會進行切換 2. 打開 F12 將他改為不存在的圖片後,並在後面使用 `onerror = alert()` 使網頁發出 alert ![image](https://hackmd.io/_uploads/ryMhAB160.png) <!-- NISRA{X55_1s_50_c0o0o01!} --> ### Invisible - 101 1. 點開題目連結,打開F12找尋可疑的東西 2. 在主頁點開右上角的選單後,再次檢查F12,發現有個文字顏色被設定成跟背景一樣的黑色的顏文字超連結 ![image](https://hackmd.io/_uploads/SygUEik2R.png) 3. 點按(•̀ω•́)y連結,來到看似一片空白的網頁,但是從F12可以看到有一張QRcode的visibility屬性被設定成hidden,也就是圖片被藏起來了,不可見的意思 ![image](https://hackmd.io/_uploads/B1TRPjk2A.png) 4. 可以透過修改visibility屬性,將hidden改成visible,圖片就會顯現出來了 或是把鼠標移到圖片連結上,也能預覽圖片![image](https://hackmd.io/_uploads/BJlWKiJhR.png) 5. 用手機掃描QRcode得到flag #### 不需要用手機掃描QRcode的方法 在body標籤裡面的script標籤中,可以明顯看到有一坨用```[]()!+```組合成的東西 ![image](https://hackmd.io/_uploads/ByzAFjk2A.png) 這個詭異的東西其實是一種叫做<b>JSFuck</b>的JavaScript的寫法,可以用查詢線上加密解密工具的方式,去Google搜尋JSFuck decode,利用線上工具解密,就能得到這串東西寫了什麼JavaScript的語法 解密前: ![image](https://hackmd.io/_uploads/B1Hd2okhC.png) 解密後,就可以從這串JavaScript複製flag了```var elText = "NISRA{ja^asCr1pt_w1th_qrC0de}";``` ![image](https://hackmd.io/_uploads/H1Bj2o12A.png) ### GETGETGET - 101 1. 點開題目連結後,畫面上看到的是用<b>PHP</b>這個後端語言寫的程式碼,它在做的動作是判斷使用者輸入的帳密是否正確 2. 閱讀程式碼可以發現它多次提到<b>GET</b>這個請求方法,也就是說我們現在看到的PHP程式碼,就是前端那邊的表單標籤\<form>的action屬性,所設定的目的地(將使用者輸入的資料傳送到這個PHP檔案做處理) 也可以發現用來儲存使用者輸入的帳號的變數名稱為"user",密碼則是"password",![image](https://hackmd.io/_uploads/HyP4lnynA.png) 且最終user必須等於"admin"、password必須等於"ji32k7au4a83",才能通過if判斷式,得到flag訊息![image](https://hackmd.io/_uploads/HyBBg3kh0.png) 3.知道了帳號密碼各自的變數名稱和正確數值後,可以利用GET方法的特性,修改URL,在網址後方加上"?"再打上帳號密碼的參數和數值,就能在不依靠輸入框的情況下,向後端傳送"使用者輸入的內容" ```http://chall2.nisra.net:41016?user=admin&password=ji32k7au4a83``` 在下方文字訊息中得到flag ![image](https://hackmd.io/_uploads/SyA6W2kh0.png) ### 🍪 - 101 1. 透過題目標題的餅乾emoji,聯想到這題應該是跟網頁的cookie有關 2. 點開題目連結,打開F12,找到Application的分頁,點進去後在左側欄位找到Cookies 點進去就能看到名為Flag的cookie,其值為```NISRA%7By0u_F1nd_53t_C0ok135%7D``` ![image](https://hackmd.io/_uploads/S13gSh1n0.png) 補充: flag中的```%7B```跟```%7D```是左右大括號{}各自在<b>URL編碼</b>後的結果,URL編碼的特徵就是有百分比的符號%為開頭,可以按下畫面下方的"Show URL-decoded"的框框,讓網頁自動解碼得到正確的flag格式```NISRA{y0u_F1nd_53t_C0ok135}``` ![image](https://hackmd.io/_uploads/r1VKLny20.png) #### 讓網頁噴cookie的另一種方法 1. 在JavaScript中,可用```document.cookie```讀取cookie,搭配alert()或console.log()進行輸出 2. 去到F12的Console分頁,在這裡打上JavaScript指令,得到flag(但記得"{}"要進行URL解碼才是正確的flag格式) ```alert(document.cookie)``` ![image](https://hackmd.io/_uploads/H1Zww2J20.png) ![image](https://hackmd.io/_uploads/BkS8wnk2C.png) 或 ```console.log(document.cookie)``` ![image](https://hackmd.io/_uploads/BJGL_nk2A.png)