Post

[CVE-2024-5324] 취약점 분석 보고서

CVE-2024-5324 WordPress의 Login/Signup Popup 플러그인에서 'import_settings' 함수에 대한 권한 확인 누락

1. CVE-2024-5324이란?

CVE ID: CVE-2024-5324
CVSS 심각도 점수: 8.8
영향을 받는 버전:  2.7.1~2.7.2

CVE-2024-5324는 WordPress의 ‘Login/Signup Popup (Inline Form + WooCommerce)’ 플러그인 버전 2.7.1부터 2.7.2까지에서 발견된 취약점이다. 이 취약점은 ‘import_settings’ 함수에 대한 권한 확인이 누락되어 있어, 인증된 공격자가 Subscriber 이상의 권한으로 임의의 사이트 옵션을 변경할 수 있게 한다. 이를 통해 새로운 사용자 등록을 활성화하고, 신규 사용자의 기본 역할을 관리자(Admin)로 설정하는 등의 행위가 가능하다.

CVE-2024-5324

2. 환경구축

XAMPP 3.3.0, Wordpress 6.6.2, Login/Signup Popup 2.7.2

image.png

Login/Signup Popup 2.7.2 버전을 설치하고

shortcode를 이용해 로그인 및 회원 가입 페이지를 작성한다.

image.png

그 후, 회원 가입을 통해 공격에 사용할 계정을 만들어준다.

3. 분석

Login/Signup 설정에 들어가면 사용자 회원 가입을 허용, 회원 가입 시 설정 권한 등

다양한 설정값들이 존재하는데 이러한 설정값들을 아래 사진과 같이 내보내거나 불러올 수 있다.

image.png
(설정 값 내보내기)

image.png
(설정 값 불러오기)

import 할 때 패킷을 잡아보면

image.png

post형식으로 import파라미터에 설정 값이 담겨 전송된다.

이때 설정 값을 불러오는 데 사용되는 함수가 import_settings 함수인데

class-xoo-admin-settings.php를 확인해 보면 import_settings 함수에 권한을 확인하는 기능이 없는 것을 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
public function import_settings(){
		
		$settings  = $_POST['import'];
	
		$options = json_decode( html_entity_decode( stripslashes ($settings ) ), true );

		foreach ( $options as $key => $value ) {
			update_option( $key, $value );
		}
			
		die();

	}

이러한 권한 확인 기능이 없으면 subscriber 권한의 일반 사용자가 해당 설정을 변경할 수 있다.

4. POC

현재 설정 값은 회원 가입 불가능, 회원 가입 시 권한은 subscriber로 설정되어 있으며,

subscriber 권한을 가진 ‘123’ 계정으로 진행을 했다.

image.png
image.png

해당 계정으로 /wordpress/wp-admin/admin-ajax에 아래와 같은 파라미터를 전송해보면

1
action=xoo_admin_settings_import&xoo_ff_nonce=&slug=easy-login-woocommerce&import={"xoo-el-gl-options":{"m-en-reg":"yes","m-user-role":"administrator"}}

image.png

설정 값이 변경되는 걸 확인할 수 있다.

image.png

이러한 패킷을 보내고 회원 가입을 진행하면

image.png

관리자 권한을 가진 계정으로 회원 가입이 진행되는 걸 확인할 수 있다.

image.png

5. 패치

2.7.3 버전부터는 nonce를 확인해 사용자를 확인한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public function import_settings(){
	
	                // Check for nonce security     
	                if ( !wp_verify_nonce( $_POST['xoo_ff_nonce'], 'xoo-ff-nonce' ) ) {
	                        die('cheating');
	                }
	
	                if( !current_user_can( $this->capability ) ) return;
	               
	                $settings  = $_POST['import'];
	       
	                $options = json_decode( html_entity_decode( stripslashes ($settings ) ), true );
	
	                foreach ( $options as $key => $value ) {
                         update_option( $key, $value );
	                }
	                       
	                die();
	
	        }
This post is licensed under CC BY 4.0 by the author.