我们先了解一下PHP文件包含的函数,包含的文件会被当成PHP代码执行
include_once() 包含载入的文件会有内部判断机制是否“前面代码”已经包含载入过,如果载入,就不再载入。
include()包含载入的文件不判断是否重复包含,只要执行include(),就会包含一次,文件包含失败时会报一个"错误",然后继续执行代码。
require_once()函数会有内部判断机制是否“前面代码”已经包含载入过,如果载入,就不再载入。包含载入文件失败时候,报错并立即终止执行,不会执行后续代码。
require()函数不会进行判断是否重复包含,包含载入文件失败时候,报错并立即终止执行,不会执行后续代码
// The page we wish to display
$file = $_GET[ 'page' ];
?>
index.php文件关键代码;这个就是接收low等级代码中$file变量的
// if( count( $_GET ) )
if( isset( $file ) )
include( $file );
else {
header( 'Location:?page=include.php' );
exit;
}
Low等级代码什么也没有过滤。index.php文件直接Include包含了low等级代码中$file的值。
可以使用伪协议,远程文件包含来getshell。远程文件包含需要在 php.ini配置文件开启这两个参数allow_url_fopen=On;allow_url_include=On
用远程文件包含来演示一下
在web根目录下放了1.txt文件里面写入一句话。
直接包含1.txt文件的地址。这里远程文件包含就成功了。
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );
?>
分析代码
str_replace() 函数以其他字符替换字符串中的一些字符,$file变量中如果存在http://,https://就会替换成空。
这里是可以绕过的 拼接绕过 htthttp://p:// => http://; …/./ => …/
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
分析代码
fnmatch() 函数根据指定的模式来匹配文件名或字符串。语法fnmatch(pattern,string,flags)pattern必需设置规定要检索的模式。string必需设置规定要检查的字符串或文件。
这里就是检测 传递过来的字符串是不是 以file开头的。这里的话 伪协议和远程文件包含都不行。只能使用本地包含,可以利用日志文件来getshell。
在url中写上一句话,地址栏中url会记录在日志文件中而url写上了一句话
找到配置文件直接本地包含日志文件。直接访问会转码的 用burp抓包修改就行
访问日志文件
// The page we wish to display
$file = $_GET[ 'page' ];
// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
这里if判断全都写死了 如果包含的不是file1.php文件之类就会报错