PHP伪协议的几种使用姿势
常见的文件包含函数
首先归纳下常见的文件包含函数:include
、require
、include_once
、require_once
、highlight_file
、show_source
、readfile
、file_get_contents
、fopen
、file
。
1 | # 默认开启,该选项为on便是激活了URL形式的fopen封装协议使得可以访问URL对象文件等。 |
file://协议
file在allow_url_fopen和allow_url_include均off的情况下也可使用。
file://
通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响。
文件系统是PHP使用的默认封装协议,展现了本地文件系统。 当指定了一个相对路径(不以/、\、\或 Windows 盘符开头的路径)提供的路径将基于当前的工作目录。 在很多情况下是脚本所在的目录,除非被修改了。 使用 CLI 的时候,目录默认是脚本被调用时所在的目录。
php://协议
不需要开启allow_url_fopen,仅php://input、php://stdin、php://memory和php://temp需要开启allow_url_include。
php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter
和php://input
。php://filter
用于读取源码,php://input
用于执行php代码。
php://input
是个可以访问请求的原始数据的只读流。但是当enctype="multipart/form-data"
的时候php://input
是无效的。
php://filter
在allow_url_fopen
和allow_url_include
均off
也能正常使用。参数列表如下
例题【读取源代码】- php://filter
import requestsimport bs4def next_page(url): file = open(‘1.html’, encoding=’utf-8’) parser = bs4.BeautifulSoup(file.read(), ‘html.parser’) btn = parser.select(‘.nextLink > a[title]’) next = btn[0].get(‘href’) nextURL = url + next return nextURLurl = ‘https://xkcd.in/'link = urlnum = eval(input(“请输入你需要下载的页数:”))print(“正在下载中……”)for i in range(0, num): # 获取该网页的HTML文件 web_req = requests.get(link) html_file = open(‘1.html’, ‘wb’) for chunk in web_req.iter_content(10000): html_file.write(chunk) html_file.close() # 获取该网页HTML文件的img标签 html = open(‘1.html’, encoding=’utf-8’) soup = bs4.BeautifulSoup(html.read(), ‘html.parser’) elems = soup.select(‘img[title]’) # 获取图片的资源地址 payload = elems[0].get(‘src’) title = elems[0].get(‘title’) # 重组url定位到图片的地址 src = url + payload img_req = requests.get(src) file_ad = ‘img/‘ + title.replace(“?”, “”) + ‘.jpg’ jpg = open(file_ad, ‘wb’) for chunk in img_req.iter_content(10000): jpg.write(chunk) print(“正在下载:” + title) link = url link = next_page(link) html.close() jpg.close()print(“下载成功!”)python
使用php://filter
读取源代码并进行base64编码输出。
payload为
1 | ?file=php://filter/read=convert.base64-encode/resource=/flag |
得到的数据如下图所示,进行base64解码即可得到flag
。
例题【远程包含】- php://input
看下phpinfo,发现两个都开了。
用php://input
,然后post我们需要执行的代码,看下当前目录的文件。只有index.php
和phpinfo.php
。
去上一级看看吧,发现了flag
文件。
读取一下,拿到flag。
data://协议
根据官方文档,使用data://协议必须满足allow_url_fopen和allow_url_include都开启。
以下代码打印data://的内容。
1 |
|
获取媒体类型。
1 |
|
下面是是两个实例。
1 | http://127.0.0.1/test.php?file=data://text/plain,<?php phpinfo()?> |