湖农大邀请赛shell_rce漏洞复现

湖农大邀请赛 shell_rce 复现

在 2023 年湖南农业大学邀请赛的线上初赛中,有一道 shell_rce 题,本文将复现该题。

题目内容,打开即是代码:

<?phpclass shell{public $exp;public function __destruct(){$str = preg_replace('/[^\W]+\((?R)?\)/', '', $this->exp);$code = substr($str , 0, 1);if(preg_match("/^[$code]+$/",$str)){eval($this->exp." hello world!"); }}
}if(!isset($_GET['exp'])){highlight_file(__FILE__);
}if(!preg_match('/^[Oa]|get/i',$_GET['exp'])){unserialize($_GET['exp']);
}

注意到在反序列化之前先进行了一个判断

preg_match('/^[Oa]|get/i',$_GET['exp'])

这段代码使用 PHP 的 preg_match 函数对 $_GET[‘exp’] 变量进行正则表达式匹配。具体而言,该正则表达式为 “1|get”,其解释如下:

  • ^ 表示匹配字符串的开头
  • [Oa] 表示匹配 O 或 a 这两个字符中的任意一个
  • | 表示逻辑或,即要么匹配开头的 O 或 a,要么匹配 get
  • i 表示不区分大小写

因此,该正则表达式可以匹配的字符串包括:

  • 以 O 或 a 开头的任意字符串
  • 包含 get 的任意字符串,不区分大小写

在本代码中,若 $_GET[‘exp’] 变量与上述正则表达式匹配成功,则返回 true,否则返回 false。

如此一来,常见的序列化字符串和数组绕过的方法都不管用了。

C 开头的绕过

推荐博客:

https://fushuling.com/index.php/2023/03/11/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B8%ADwakeup%E7%BB%95%E8%BF%87%E6%80%BB%E7%BB%93/

这里只用 ArrayObject() 函数做演示,具体操作如下:

$exp = new shell();
$arr = array("exp"=>$exp);
$ao = new ArrayObject($arr);
echo serialize($ao);

这段 PHP 代码的作用如下:

  1. 创建一个名为 $exp 的对象,该对象是 shell 类的一个实例。

  2. 创建一个名为 $arr 的数组,其中只有一个元素,即键名为 “exp”,键值为 $exp。

  3. 使用 PHP 内置函数 ArrayObject 对 $arr 进行实例化,获得一个名为 $ao 的 ArrayObject 对象。

  4. 调用 PHP 内置函数 serialize 将 $ao 序列化,即将其转换成可以存储或传输的字符串形式,输出结果到页面上。

通过以上操作,即可将序列化字符串变成以 C 开头的形式,绕过第一个检测。

输出结果:

C:11:"ArrayObject":59:{x:i:0;a:1:{s:3:"exp";O:5:"shell":1:{s:3:"exp";N;}};m:a:0:{}}

无参函数 RCE

在 shell 类的 __destruct 方法中,有这样的过滤机制:

$str = preg_replace('/[^\W]+\((?R)?\)/', '', $this->exp);

会将该类中的属性 exp 作一个过滤

该段代码使用 PHP 的 preg_replace 函数对 $this->exp 字符串进行正则表达式替换。具体而言,该正则表达式为 “[^\W]+\((?R)?\)”,其解释如下:

  • [^\W]+ 表示匹配一个或多个非特殊字符(即字母或数字),这里的 ^\W 表示取反后表示非特殊字符
  • ( 表示匹配左括号
  • (?R) 表示匹配一个递归到起始符号(即 “(?R)”)的表达式,即匹配一个嵌套的模式。所以该正则表达式能够处理有括号嵌套的情况
  • ) 表示匹配右括号

因此,该正则表达式可以匹配的字符串为类似于 " functionName(args) " 这样的字符串,并且支持函数嵌套,例如:functionName1(functionName2()) 。其实际含义是匹配一个函数名后紧跟着一对括号,其中可以有递归式的参数列表。

当匹配到这种无参函数格式的字符串时,就会将其替换为空。

使用无参函数的话,所有的值都会被替换为空。假设函数有参,那么参数部分将会被保留,但是这样的话就无法通过后面的过滤了,具体为什么后面会讲。

因此,在 C 绕过的基础上,可以构造如下的 payload :

$exp->exp = "var_dump(scandir(current(localeconv())));"

这个 PHP 嵌套函数的作用如下:

  1. localeconv() 函数返回当前设置的地区的格式化信息,包括货币符号、小数点符号等。它返回一个数组,其中包含了与当前地区相关的格式化参数,该函数返回的第一个元素的值通常是小数点 “.” 。

  2. current() 函数用于获取数组中的当前元素的值。在这里,它用于获取 localeconv() 函数返回的数组的第一个元素的值,即一个小数点。

  3. scandir() 函数用于获取指定目录中的文件和文件夹列表。它接受一个路径作为参数,并返回一个包含指定目录中所有文件和文件夹的数组。scandir(".") 表示获取当前目录下的文件列表。

因此,该代码的作用是获取当前地区的第一个格式化参数(通常是小数点符号),然后将该参数作为路径传递给 scandir() 函数,从而获取该路径下的文件和文件夹列表。最终,使用 var_dump() 函数将该列表输出到页面上,以便查看它们的详细信息。

因为 eval 函数的参数结尾必须要带分号,所以该字符串的末尾添加了分号,如此一来,str 字符串就只是一个分号了

__halt_compiler() 中断 eval() 函数的执行

在无参函数绕过之后,又进行了一次过滤:

$str = preg_replace('/[^\W]+\((?R)?\)/', '', $this->exp);
$code = substr($str , 0, 1);
if(preg_match("/^[$code]+$/",$str))
{eval($this->exp." hello world!"); 
}

这段 PHP 代码的作用如下:

  1. 使用 substr 函数从字符串 $str 中取出第一个字符,并将其赋值给变量 $code。

  2. 使用正则表达式 “/^[$code]+$/” 对字符串 s t r 进行匹配。其中, " ‘ [ str 进行匹配。其中,"`^[ str进行匹配。其中,"[code]+`" 匹配以 $code 中的字符开头,并且由 c o d e 中的字符组成的任何长度的字符串, " code 中的字符组成的任何长度的字符串," code中的字符组成的任何长度的字符串,"" 表示匹配到字符串结尾。总的来说,该正则表达式表示 $str 只包含 $code 中的字符。

  3. 如果匹配成功,即 $str 只包含 $code 中的字符,那么执行 eval 函数,将 $this->exp 和字符串 “hello world!” 连接在一起作为 PHP 代码执行。eval 函数可以将字符串作为 PHP 代码执行,因此这里相当于在执行 $this->exp 和 “hello world!” 的拼接结果。如果 $this->exp 中含有函数调用等需要被执行的代码,则会在这里被执行。

  4. 如果正则表达式匹配失败,即 $str 中含有 $code 中未包含的字符,则不执行 eval 函数。

已知 str 只是一个分号,那么 code 就也是一个分号,这样就能通过后面的过滤了。假如 str 不是只有分号的话,这里就过不去,所以上面要用无参函数。

到这里我们知道,$this->exp 字符串中有且只能有无参函数和分号,有多少个都可以,怎么排列都可以,但是不能有其他的东西。

但是问题来了:

eval($this->exp." hello world!"); 

这段代码做一个字符串拼接,导致 eval 函数无法正常执行,当时想了好久,知道赛后放 wp 才知道,__halt_compiler() 函数可以中断 eval() 的执行,这是连 exit() 都做不到的事。比如说:

eval(a();__halt_compiler(); hello world!)

那么 eval 函数执行完 a() 函数后,执行到 __halt_compiler() 函数时就会中断,不再执行后面的代码,也不会因为后面的代码不符合规范而报错。

据此,构造最终的 payload :

$exp = new shell();
$exp->exp = "var_dump(scandir(current(localeconv())));__halt_compiler();";
$arr = array("exp"=>$exp);
$ao = new ArrayObject($arr);
echo serialize($ao);

本地成功输出:

在这里插入图片描述

想要读取文件的话,修改 $exp->exp 的值就可以了。

官方的 wp 中使用 array_rand() 随机获取当前目录下的文件内容。

官方 wp :

var_dump(readfile(array_rand(array_flip(scandir(current(localeconv()))))));

array_flip() 反转数组中的键值对,即将数组中的每个值作为键,原来的键作为新的值。

array_rand() 随机获取反转后的数组中的一个键,即获取当前文件夹下随机一个文件或文件夹的名称。

输出结果:

在这里插入图片描述
在上面查看查看当前目录下文件时,返回的数组中还有 “.” 和 “…” 两个值,所以上面的 payload 可能会不成功,需要多试几次。


  1. Oa ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

KaiwuDB × 国网山东综能 | 分布式储能云边端一体化项目建设

项目背景 济南韩家峪村首个高光伏渗透率台区示范项目因其所处地理位置拥有丰富的光照资源&#xff0c;该区域住户 80% 以上的屋顶都安装了光伏板。仅 2022 年全年&#xff0c;光伏发电总量达到了百万千瓦时。 大量分布式光伏并网&#xff0c;在输出清洁电力的同时&#xff0c…

Gerrit 提交报错missing Change-Id in message footer

直接执行提示的命令&#xff1a; gitdir$(git rev-parse --git-dir); scp -p -P 29418 liyjgerrit.ingageapp.com:hooks/commit-msg ${gitdir}/hooks/ 如果报错&#xff1a; subsystem request failed on channel 0 在.git/hooks目录下看有没有生成commit-msg文件&#xff…

测序名词解释

测序深度&#xff08;Sequencing Depth&#xff09;是指&#xff1a;测序得到的碱基总量&#xff08;bp&#xff09;与基因组&#xff08;转录组或测序目标区域大小&#xff09;的比值&#xff0c;是评价测序量的指标之一。 测序深度的计算公式为&#xff1a; 测序深度 &…

一点技术细节

匈牙利算法&#xff1a; 14-4: 匈牙利算法 Hungarian Algorithm_哔哩哔哩_bilibili 课件&#xff1a;https://github.com/wangshusen/AdvancedAlgorithms.git SWin transformer&#xff1a; Swin Transformer论文精读【论文精读】_哔哩哔哩_bilibili patch:灰色 窗口&…

数据结构之---- 回溯算法

数据结构之---- 回溯算法 什么是回溯算法&#xff1f; 回溯算法是一种通过穷举来解决问题的方法&#xff0c;它的核心思想是从一个初始状态出发&#xff0c;暴力搜索所有可能的解决方案&#xff0c;当遇到正确的解则将其记录&#xff0c;直到找到解或者尝试了所有可能的选择都…

day01-报表技术POI

前言 报表[forms for reporting to the higher organizations]&#xff0c;就是向上级报告情况的表格。简单的说&#xff1a;报表就是用表格、图表等格式来动态显示数据&#xff0c;可以用公式表示为&#xff1a;“报表 多样的格式 动态的数据”。 1、开发环境搭建 功能说…

图扑物联 | WEB组态可视化软件

什么是组态&#xff1f; 组态的概念来自于20世纪70年代中期出现的第一代集散控制系统&#xff08;Distributed Control System&#xff09;&#xff0c;可理解为“配置”、“设置”等&#xff0c;是指通过人机开发界面&#xff0c;用类似“搭积木”的简单方式来搭建软件功能&a…

stm32H库的内部FLASH读写操作与结构体数组数据写入与读取

stm32H库的内部FLASH读写操作与结构体数组数据写入与读取 1.软硬件准备2.关于STM32的Flash的一些说明3.实验结果 参考博主-STM32系列(HAL库)——内部FLASH读写实验 1.软硬件准备 软件&#xff1a;CubeMX、SSCOM&#xff08;串口调试助手&#xff09; 硬件&#xff1a;SMT32F…

动态通讯录(并不难都能拿下)

文章目录 &#x1f680;前言&#x1f680;通讯录实现动态通讯录的初期准备模块化框架搭建 &#x1f680;实现接口函数 &#x1f680;前言 铁子们好啊&#xff01;今天咱们来整一个有意思的玩意——通讯录&#xff0c;相信大家对通讯录并不陌生&#xff0c;那接下来就跟着阿辉把…

基于ssm小区疫情防控管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本小区疫情防控管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据…

微信小程序集成腾讯地图

微信小程序集成腾讯地图 微信小程序集成腾讯地图&#xff0c;实现用户附近停车位搜索显示。 腾讯开发者Key申请 官方地址&#xff1a;https://lbs.qq.com/ 下载工具JS 微信小程序JS代码 // pages/check-services.js const app getApp() // 引入SDK核心类 var QQMapWX …

Nginx配合Vue的history模式

加上一行代码就行&#xff1a; try_files $uri $uri/ /index.html;

PyQt6 QTreeWidget树控件

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计46条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

Easy Excel生成复杂下Excel模板(下拉框)给用户下载

引言 文件的下载是一个非常常见的功能&#xff0c;也有一些非常好的框架可以使用&#xff0c;这里我们就介绍一种比较常见的场景&#xff0c;下载Excel模版&#xff0c;导入功能通常会配有一个模版下载的功能&#xff0c;根据下载的模版&#xff0c;填充数据然后再上传。 需求…

TrustGeo代码理解(七)preprocess.py

代码链接:https://github.com/ICDM-UESTC/TrustGeo 一、导入各种模块和数据库 # Load data and IP clusteringimport math import random import pandas as pd import numpy as np import argparse from sklearn import preprocessing from lib.utils import MaxMinScaler …

设计模式——外观模式(结构型)

引言 外观模式是一种结构型设计模式&#xff0c; 能为程序库、 框架或其他复杂类提供一个简单的接口。 ​ 问题 假设你必须在代码中使用某个复杂的库或框架中的众多对象。 正常情况下&#xff0c; 你需要负责所有对象的初始化工作、 管理其依赖关系并按正确的顺序执行方法等。…

C#动态生成带参数的小程序二维码

应用场景 在微信小程序管理后台&#xff0c;我们可以生成下载标准的小程序二维码&#xff0c;提供主程序入口功能。在实际应用开发中&#xff0c;小程序二维码是可以携带参数的&#xff0c;可以动态进行生成&#xff0c;如如下场景&#xff1a; 1、不同参数决定的显示界面不同…

MQTT中的保留消息(Retained Message)

一条保留消息是MQTT中保留标志设置为true的一条普通消息。代理&#xff08;broker&#xff09;为对应的主题保留最后的保留消息及对应的QoS。每一个订阅了该主题的客户端在订阅之后会马上收到这个保留消息。代理&#xff08;broker&#xff09;为每个主题只存储一条保留消息。本…

Docker本地镜像发布到阿里云或私有库

本地镜像发布到阿里云流程 &#xff1a; 1.自己生成个要传的镜像 2.将本地镜像推送到阿里云: 阿里云开发者平台:开放云原生应用-云原生&#xff08;Cloud Native&#xff09;-云原生介绍 - 阿里云 2.1.创建仓库镜像&#xff1a; 2.1.1 选择控制台&#xff0c;进入容器镜像服…

MQTT的奇妙之旅:探索RabbitMQ Web MQTT插件的威力【RabbitMQ 十一】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 MQTT的奇妙之旅&#xff1a;探索RabbitMQ Web MQTT插件的威力 前言第一&#xff1a;揭秘RabbitMQ Web MQTT插件背景和目的&#xff1a;MQTT 协议简介&#xff1a;WebSockets 和 MQTT 的融合&#xff1…