频道栏目
首页 > 安全 > 网站安全 > 正文

安全模式下exec等函数安全隐患

2009-05-30 11:46:11           
收藏   我要投稿

当safe_mode=on且safe_mode_exec_dir为空时[默认为空],php在处理这一过程中存在安全隐患,在windows下exec()/system()/passthru()可以通过引入来执行程序,绕过安全模式

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

一 前言

就在昨天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()函数为例分析下源码:

PHP代码
C++代码   
// 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 = ;      
            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是80vuldir,那么这部分取得的值是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的话,80vuldir经过上面的处理为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;&

相关TAG标签 隐患 函数 模式
上一篇:Discuz!密码加密方式
下一篇:dedecms 5.3的不足之处,加一鸡肋小漏!
相关文章
图文推荐
文章
推荐
热门新闻

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站