POC
这题对于我来说有难度,不看WP确实写不出来
首先题目给了源码
<?php
if(!isset($_GET['mode'])){
highlight_file(__file__);
}else if($_GET['mode'] == "eval"){
$shell = isset($_GET['shell']) ? $_GET['shell'] : 'phpinfo();';
if(strlen($shell) > 15 | filter($shell) | checkNums($shell)) exit("hacker");
eval($shell);
}
if(isset($_GET['file'])){
if(strlen($_GET['file']) > 15 | filter($_GET['file'])) exit("hacker");
include $_GET['file'];
}
function filter($var){
$banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"];
foreach($banned as $ban){
if(strstr($var, $ban)) return True;
}
return False;
}
function checkNums($var){
$alphanum = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$cnt = 0;
for($i = 0; $i < strlen($alphanum); $i++){
for($j = 0; $j < strlen($var); $j++){
if($var[$j] == $alphanum[$i]){
$cnt += 1;
if($cnt > 8) return True;
}
}
}
return False;
}
?>
从这里可以发现两个攻击点,一是eval()
函数的RCE攻击点,第二个就是include
的文件包含攻击点
RCE那里有很多过滤,很难从那里去攻击,那么只能去看include的了,这里应该要思考到include应该要包含一些我们可以利用的文件,首先日志文件是一个方向,但是日志文件太杂乱,不是那么容易就可以成功包含并且利用的;但是源码中提供了phpinfo,那么这个phpinfo就一定是有用的,没用他不会放在这里,我们查看phpinfo,可以发现里面开启了如下几个我们可以利用的功能
- session.auto_start:如果 session.auto_start=On ,则PHP在接收请求的时候会自动初始化 Session,不再需要执行session_start()。但默认情况下,这个选项都是关闭的。但session还有一个默认选项,session.use_strict_mode默认值为 off。此时用户是可以自己定义 Session ID 的。比如,我们在 Cookie 里设置 PHPSESSID=ph0ebus ,PHP 将会在服务器上创建一个文件:/tmp/sess_ph0ebus”。即使此时用户没有初始化Session,PHP也会自动初始化Session。 并产生一个键值,这个键值有ini.get(“session.upload_progress.prefix”)+由我们构造的 session.upload_progress.name 值组成,最后被写入 sess_ 文件里。
- session.save_path:负责 session 文件的存放位置,后面文件包含的时候需要知道恶意文件的位置,如果没有配置则不会生成session文件
- session.upload_progress_enabled:当这个配置为 On 时,代表 session.upload_progress 功能开始,如果这个选项关闭,则这个方法用不了
- session.upload_progress_cleanup:这个选项默认也是 On,也就是说当文件上传结束时,session 文件中有关上传进度的信息立马就会被删除掉;这里就给我们的操作造成了很大的困难,我们就只能使用条件竞争(Race Condition)的方式不停的发包,争取在它被删除掉之前就成功利用
- session.upload_progress_name:当它出现在表单中,php将会报告上传进度,最大的好处是,它的值可控
- session.upload_progress_prefix:它+session.upload_progress_name 将表示为 session 中的键名
综上所述,这种利用方式需要满足下面几个条件:
- 目标环境开启了session.upload_progress.enable选项
- 发送一个文件上传请求,其中包含一个文件表单和一个名字是PHP_SESSION_UPLOAD_PROGRESS的字段
- 请求的Cookie中包含Session ID
注意的是,如果我们只上传一个文件,这里也是不会遗留下Session文件的,所以表单里必须有两个以上的文件上传 。
接着放上网上现成的Python脚本
session.upload_progress临时文件包含漏洞利用脚本