
CVE-2024-11972 in Hunk Companion <1.9.0은 인증되지 않은 공격자가 안전하지 않은 REST API 엔드포인트를 악용하고 취약한 플러그인을 설치하여 RCE, SQLi, XSS 및 백도어 위험을 초래할 수 있습니다.
CVE-2024-11972는 Hunk Companion 워드프레스 플러그인 버전 1.9.0 미만에서 발견된 치명적인 취약점입니다. 이 결함은 인증되지 않은 공격자가 부적절하게 권한이 부여된 REST API 엔드포인트를 악용하여 WordPress.org 저장소에서 플러그인을 설치하고 활성화할 수 있게 합니다. 여기에는 오래되었거나 알려진 취약점이 있는 플러그인도 포함됩니다. 이 취약점을 악용하면 원격 코드 실행, SQL 인젝션, XSS 또는 관리자 백도어와 같은 심각한 보안 위험이 발생할 수 있습니다.
이 취약점을 악용하는 일반적인 예는 WP Query Console 플러그인과 함께 사용하는 것입니다. 이 익스플로잇을 통해 설치되면, 플러그인은 워드프레스 내에서 SQL 쿼리를 실행할 수 있는 콘솔 인터페이스를 제공하여 데이터 도난, 백도어 생성 및 완전한 데이터베이스 손상을 가능하게 합니다.
필요한 Python 라이브러리 -> argparse, requests, urljoin
options:
-h, --help show this help message and exit
-u URL, --url URL Base URL of the WordPress site (default: http://localhost/wordpress/).
-p PLUGIN, --plugin PLUGIN
Plugin name to install (default: classic-editor).
<insert wordpress URL> -p <insert plugin name>취약한 엔드포인트 /wp-json/hc/v1/themehunk-import는 Daniel Rodriguez가 진행 중인 조사의 일환으로 액세스 로그를 분석하는 과정에서 처음 식별되었습니다.
이 정보를 바탕으로 임포트 엔드포인트의 소스 코드 내부를 살펴볼 수 있습니다.
/import/core/class-installation.php 파일 내부에서 다음 줄을 확인할 수 있습니다:
204 | $temp_file = download_url('https://downloads.wordpress.org/plugin/'.$slug.'.zip');
HUNK_COMPANION_SITES_BUILDER_SETUP 클래스는 입력 파라미터에 기반하여 무료 및 프리미엄 유형을 모두 처리하며 워드프레스 플러그인 및 테마의 설치 및 활성화를 관리합니다.
이 클래스는 플러그인이나 테마가 설치되었는지 또는 활성화되었는지 동적으로 확인하고, 누락된 경우 필요한 파일을 다운로드하여 압축을 풀고 워드프레스 핵심 함수를 사용하여 활성화합니다.
이 하드코딩된 기능은 플러그인이 워드프레스 저장소에서 어떤 플러그인(제거되었거나 중단된 것까지)도 다운로드할 수 있게 하여 공격자가 취약한 플러그인을 악용하여 공격할 기회를 제공합니다.
문제를 더 깊이 살펴보기 위해 /import/app/app.php 내부를 확인할 수 있습니다.
버전 1.8.0 | 1.8.7 | 1.9.0에서 도입된 다양한 수정 사항을 비교해 보겠습니다. 각 버전은 또 다른 보안 계층을 추가했습니다.
register_rest_route( 'hc/v1', 'themehunk-import', array(
'methods' => 'POST',
'callback' => array( $this, 'tp_install' ),
'permission_callback' => '__return_true',
) );
permission_callback은 항상 true를 반환하므로 모든 사용자 또는 인증되지 않은 행위자가 POST 요청을 사용하여 엔드포인트에 접근할 수 있습니다.
어떤 종류의 Nonce 검증이나 인증 프로세스가 없기 때문에 공격자는 필요한 권한을 우회하고 원하는 플러그인을 직접 설치할 수 있습니다.
버전 1.8.7에서는 이전 버전에 존재하던 결함을 해결하기 위해 여러 보안 개선이 도입되었지만,
엔드포인트 /hc/v1/themehunk-import와 전체 구현에는 여전히 심각한 결함이 있습니다:
public function register_routes() {
register_rest_route( 'hc/v1', 'themehunk-import', array(
'methods' => 'POST',
'callback' => array( $this, 'tp_install' ),
'permission_callback' => function () {
// Check if the user is logged in
if ( ! is_user_logged_in() ) {
return new WP_REST_Response( 'Unauthorized: User not logged in', 401 );
}
// Debug: Log the user role and capabilities to see what they have
$current_user = wp_get_current_user();
// error_log( 'Current user: ' . $current_user->user_login );
// error_log( 'User roles: ' . implode( ', ', $current_user->roles ) );
// error_log( 'User capabilities: ' . print_r( $current_user->allcaps, true ) );
// Ensure the user has the 'install_plugins' capability
if ( ! current_user_can( 'install_plugins' ) ) {
return new WP_REST_Response( 'Unauthorized: Insufficient capabilities', 401 );
}
// Get the nonce from the request header
$nonce = $request->get_header('X-WP-Nonce');
// Verify the nonce
if ( ! wp_verify_nonce( $nonce, 'hc_import_nonce' ) ) {
return new WP_REST_Response( 'Unauthorized: Invalid nonce', 401 );
}
return true; // Permission granted
이 버전은 사용자가 로그인했는지 확인(is_user_logged_in())하고 적절한 권한(current_user_can('install_plugins'))을 가지고 있는지 확인하며, 그렇지 않은 경우 401 Unauthorized 응답을 반환하지만, 여전히 해결되지 않은 주요 문제를 간과합니다.
워드프레스의 permission_callback 평가 로직은 다음과 같습니다:

즉, 올바른 응답은 다음 중 하나여야 합니다 - true | false | WP_Error.
문제는 반환된 WP_REST_Response가 불리언도 아니고 WP_Error도 아니라는 점에서 발생합니다. 워드프레스가 이를 거부(false)나 오류(WP_Error)로 해석하지 않기 때문에 암시적으로 수락하고 인증되지 않은 사용자에게 접근을 허용할 수 있어, 본질적으로 주요 문제를 해결하지 못합니다.
버전 1.9.0은 문제를 성공적으로 해결하여 취약점을 더 이상 악용할 수 없게 만들었습니다:
public function register_routes() {
register_rest_route( 'hc/v1', 'themehunk-import', array(
'methods' => 'POST',
'callback' => array( $this, 'tp_install' ),
'permission_callback' => function () {
// Check if the user is logged in
if ( ! is_user_logged_in() ) {
return false;
}
// Debug: Log the user role and capabilities to see what they have
$current_user = wp_get_current_user();
// error_log( 'Current user: ' . $current_user->user_login );
// error_log( 'User roles: ' . implode( ', ', $current_user->roles ) );
// error_log( 'User capabilities: ' . print_r( $current_user->allcaps, true ) );
// Ensure the user has the 'install_plugins' capability
if ( ! current_user_can( 'install_plugins' ) ) {
return false;
}
// Get the nonce from the request header
$nonce = $request->get_header('X-WP-Nonce');
// Verify the nonce
if ( ! wp_verify_nonce( $nonce, 'hc_import_nonce' ) ) {
return false;
}
return true; // Permission granted
이 버전에서는 사용자가 로그인하지 않았거나 올바른 권한이 없을 경우 적절한 false 값이 반환되어, permission_callback이 무단 접근을 올바르게 거부하므로 익스플로잇이 더 이상 유효하지 않게 됩니다.