PHP项目&RCE安全&调试&追踪&代码执行&命令执行
常见漏洞关键字
SQL注入:select、insert、update、mysql_query、mysqli等
文件上传:$_FILES、type="file"、上传、move_uploaded_file()等
XSS跨站:print、print_r、echo、sprintf、die、var_dump、var_export等
文件包含:include、include_once、require、require_once等
代码执行:eval、assert、preg_replace、call_user_func、call_user_func_array等
命令执行:system、exec、shell_exec、``、passthru、popen等
变量覆盖:extract、parse_str、variables、$$等
反序列化:serialize、unserialize、__construct、__destruct等
其他漏洞:unlink、file_get_contents、show_source等
CNVD拿1day-RCE代码执行-ZZZPHP
根据CNVD平台,找到zzzphp存在命令执行漏洞。
有个参考链接,看一下。
要求我们首先登录后台,编辑search.html模板,加入“{if:assert($_POST[x])}phpinfo();{end if}”这段代码,然后访问search目录,并给x传参就会执行你传参的命令。复现一下。
复现成功。现在从源代码中找下原因。搜索eval关键词,只有一处,查看一下。
只有一个变量$ifstr,再往上找看到$ifstr是由变量$zcontent控制的,而$zcontent是调用parserIfLabel函数的传参,所以看下哪里调用了parserIfLabel函数。
发现是在ParserTemplate类里的parserCommom函数调用,看看哪里创建了ParserTemplate对象并且调用了parserCommom函数。
一处是/admin/save.php中的create_index函数。
这里$zcontent是通过读取$tplfile的文件获得,$tplfile=TPL_DIR.'index.html',不管TPL_DIR是哪个路径,但一定读的是index.html文件,不可由我们控制,故这里不行。
另一处是/inc/zzz_client.php中,有四个地方都调用了。
将这四处调用分为两类,第一处为一类,后面三处为一类。因为后三处的$zcontent都为load_file($tplfile,$location)。
追踪第一处$zcontent的来由。
当$location='user'时进入if循环,一开始$user_tpl为空,$uid从session中获取,如果$uid为空并且$act为reg、forget、login中的一种,则$user_tpl就根据$tplfile是否为文件来不同的赋值;如果$uid不为空且$act为userinfo或者其他情况,$user_tpl就为$incfile文件中的内容。然后把$user_tpl赋值给$zcontent。但根据尝试,此处不可行。
分析另外三处。$zcontent = load_file($tplfile,$location);跟进load_file函数。
该函数会载入对应路径的文件并返回文件内容。也就是载入此处传入的$tplfile变量中的路径的文件,并返回文件内容
跟踪$tplfile。
$tplfile的值是通过一个switch语句根据变量$location的值进行判断匹配然后赋值的,TPL_DIR为绝对路径。$location变量的值又是通过getlocation函数返回的。跟踪getlocation函数,此函数的作用就是返回get请求方式url中的最后一个文件名,例如:http://127.0.0.1/zzzphp/search.html返回的就是search
所以一开始就会在search.html文件中插入木马,实现任意命令执行。
分析: 1.当我们插入恶意语句后,getlocation函数获取url最后的文件名称为search赋值给变量$location 2.switch语句判断变量$location中的值为search,将当前绝对路径TPL_DIR和search.html拼接起来赋值给$tplfile变量 3.load_file函数去读取$tplfile变量中存放路径对应的文件的内容,并返回给$zcontent变量中 4.$zcontent变量当做参数传入parserCommom函数执行 5.parserCommom函数中定义将参数,也就是$zcontent变量,传入parserIfLabel函数来执行 6.parserIfLabel函数通过正则表达式将恶意代码{if:phpinfo()};{end if}进行匹配筛选,将筛选出来的字符串phpinfo()赋值给变量$ifstr 7.parserIfLabel函数通过eval将$ifstr中的恶意代码phpinfo()进行执行
CNVD拿1day-RCE命令执行-百家cms
根据CNVD平台,找到百家cms存在命令执行漏洞。
根据命令执行漏洞的关键函数,搜索system,总共找到5处。
一个一个查看,看哪个变量是可以由我们控制的,发现只有common.inc.php文件中的可以控制,具体代码如下。
$quality_command的前面会拼接一个"-quality",intval($scal)取的是整数值,所以$quality_command没什么用,看$file_full_path,它是传参过来的,所以需要看哪里调用了file_save函数,搜索file_save,总共有6处,一处是注释不用管。剩下5处先看common.inc.php中调用的。
第一处是file_upload函数调用。
"$file_full_path=WEB_ROOT . $path . $extpath. $filename;",其中
点击查看代码
WEB_ROOT=当前项目的绝对路径
$path = '/attachment/';
$extpath="{$extention}/" . date('Y/m/');
$filename = random(15) . ".{$extention}";
这些变量都不由我们控制,所以此处没用。再看common.inc.php中的其他几处。
都跟第一处一样,我们控制不了变量。所以在看最后一处。
源码如下:
setting.php
点击查看代码
<?php
$settings=globalSetting('weixin');
if (checksubmit()) {
$cfg = array(
'weixinname' => $_GP['weixinname'],
'weixintoken' => trim($_GP['weixintoken']),
'EncodingAESKey' => trim($_GP['EncodingAESKey']),
'weixin_appId' => trim($_GP['weixin_appId']),
'weixin_appSecret' => trim($_GP['weixin_appSecret']),
'weixin_shareaddress'=> intval($_GP['weixin_shareaddress']),
'weixin_noaccess'=> intval($_GP['weixin_noaccess'])
);
if (!empty($_FILES['weixin_verify_file']['tmp_name'])) {
$file=$_FILES['weixin_verify_file'];
$extention = pathinfo($file['name'], PATHINFO_EXTENSION);
$extention=strtolower($extention);
if($extention=='txt')
{
$substr=substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
if(empty( $substr))
{
$substr="/";
}
$verify_root= substr(WEB_ROOT."/",0, strrpos(WEB_ROOT."/", $substr))."/";
//file_save($file['tmp_name'],$file['name'],$extention,$verify_root.$file['name'],$verify_root.$file['name'],false);
file_save($file['tmp_name'],$file['name'],$extention,WEB_ROOT."/".$file['name'],WEB_ROOT."/".$file['name'],false);
if($verify_root!=WEB_ROOT."/")
{
copy(WEB_ROOT."/".$file['name'],$verify_root."/".$file['name']);
}
$cfg['weixin_hasverify']=$file['name'];
}else
{
message("不允许上传除txt结尾以外的文件");
}
}
$cfg['weixin_access_token']="";
refreshSetting($cfg,'weixin');
message('保存成功', 'refresh', 'success');
}
if(empty($settings['weixintoken']))
{
$isfirst=true;
}
include page('setting');
此处$file_full_path=WEB_ROOT."/".$file['name'],WEB_ROOT是定值,所以看$file['name']可不可以被我们控制。$file=$_FILES['weixin_verify_file'],看下如何访问setting.php,再去考虑$file的值。先看登录进去后的界面的url。
http://127.0.0.1/baijiacms/index.php?mod=site&act=manager&do=store&op=display&beid=1
这一看就是mvc架构,act对应的是目录,do对应的是文件名,op对应的是操作。
尝试去访问setting.php,setting.php位于/system/weixin/class/web目录下,所以要访问它,act=weixin,do=setting。
在源代码里输出$file['name'],上传一个文件后看他输出的是什么。
这里只能上传txt结尾的文件。
输出如下
这就说明$file['name']为我们上传的文件名字,如果想要实现命令执行,就需要用到&或者|连接符。再看common.inc.php,需要满$settings['image_compress_openscale']不为空,才会执行system语句。
全局搜索image_compress_openscale,总共4处。
主要看netattach.php,如果image_compress_openscale的value为1时,就不会为空了。
找到该文件的位置,将这个开关开启。
将文件名改为&whoami&1.txt,上传。成功执行命令。