Ssti

 
19-web-absolute_field

本ctf题目是一道flask框架的ssti注入题,题目中提示了有两个flag 一个在app.config中,另一个在根目录下

首先,我对flask框架进行了一些研究,了解了其基本的格式

flask中文文档: https://dormousehole.readthedocs.io/en/latest/

最基本的框架应用:helloworld

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
return 'Hello, World!'

之后研究其源码: def encode(line, key, key2): return ‘‘.join(chr(x ^ ord(line[x]) ^ ord(key[::-1][x]) ^ ord(key2[x]))for x in range(len(line))) ssti

file = open("/app/flag", "r")
flag = file.read()
app.config['flag'] = encode(flag,
'GQIS5EmzfZA1Ci8NslaoMxPXqrvFB7hYOkbg9y20W3',
'xwdFqMck1vA0pl7B8WO3DrGLma4sZ2Y6ouCPEHSQVT')
flag = ""

很显然,这是一串Python的定义函数encode代码,用于对存放在app/flag的flag进行加密。

比较有趣的是,这串代码的加密解密居然是一模一样的。加密一次就是加密,再加密一次就解密了。

这个加密算法的原理是异或加密算法,异或加密算法中:

a^b=c , 则 b^c=a.(a,b,c分别表示一串二进制数)

关于异或加密算法的链接:

异或加密算法

研究了这一部分以后,我把目光转向如何从app.config获取flag。 在翻阅了一些资料以后,找到了ssti的注入方法调取app.config

翻阅到的大佬的博客感觉非常的好:

CTF SSTI的讲解,很详细

调用模块:

QQ截图20191022195359

这个payload是从网上白嫖的,实际上只需要输入就行

抓取到flag是:\x18X5\x0cx\x19k}\r\x01a\x0c\x1fT\x16X?hl\x1e\OLL(n\x17\x0fi]B\x0fh8 显然这是加密过的。依据前面的代码补出python程序

def encode(line, key, key2):
    return ''.join(chr(x ^ ord(line[x]) ^ ord(key[::-1][x]) ^ ord(key2[x])) for x in range(len(line)))

flag = encode('\x18X5\x0cx\x19k}\r\x01a\x0c\x1fT\x16X?hl\x1e\\OLL(n\x17\x0fi]B\x0fh8', 'GQIS5EmzfZA1Ci8NslaoMxPXqrvFB7hYOkbg9y20W3', 'xwdFqMck1vA0pl7B8WO3DrGLma4sZ2Y6ouCPEHSQVT')

print (flag)
于是得到config处flag:Syc{this_1s_Twice_interv1ew_F14g}

另一个flag在根目录下

审计了题目这里的代码:

@app.route('/syc')
def syc():

if "'" in request.args.get('name') or '"' in request.args.get('name'):
	return "nonono"
else:
	return render_template_string(request.args.get('name'))`

意思就是访问服务器/syc的目录get传参name变量,可以让服务器执行相应命令。过滤””,’‘符号

我查阅了一些资料

安全ssti bypass分析

flask/jinja2模板注入

浅析ssti

__class__ 返回类型所属的对象
__mro__ 返回一个包含对象所继承的基类元组方法在解析时按照元组的顺序解析 
__base__ 返回该对象所继承的基类 //
__base__和__mro__都是用来寻找基类的
__subclasses__ 每个新类都保留了子类的引用这个方法返回一个类中仍然可用的的引用的列表 
__init__ 类的初始化方法 
__globals__ 对包含函数全局变量的字典的引用

然后尝试构造了第一个payload(借助request.args绕过’‘限制):

&path=/flag
().__class__.__bases__.__getitem__(0).__subclasses__()
#这部分是为了调用object基类,从而调用出file方法来操作
pop(40)(request.args.path).read()
#利用request.arg绕过''的限制
&path=/flag
#把路径设置为根目录

然后就失败了。我研究了半天到底是啥情况……结果发现这是个Python2的payload,根本没用,subclasses的pop(40)也就是file方法在Python3不存在。

所以说通过file方法调用文件显然是没用的。

当时发生了一个小插曲…..我为了找到subclasses的那个file方法,掏出了burpsuite的intruder爆破了一下靶服务器,结果服务器爆了…..后来我这个憨憨才想到是Python2和Python3的问题

不过后来我又仔细研究了一下发现了问题,看了这个博客很好,各方面都很详细

python-Flask模版注入攻击SSTI(python沙盒逃逸)

重新构造的payload:

&path=/flag
#这个调用class '_frozen_importlib._ModuleLock'来开启后面的方法寻找、读取flag文件
得到flag:Syc{this_2s_Twice_interv1ew_F14g}

感觉如果像原题一样过滤.我感觉我真的做不出来了QWQ