1. WPLMS 플러그인 (WordPress Learning Management System)
- WordPress를 사용해 LMS를 구축할 수 있도록 돕는 플러그인
※ Learning Management System : 학습 관리 시스템, 온라인으로 학생들의 학습을 관리할 수 있게 해주는 소프트웨어
2. VibeBP (Vibe BuddyPress Plugin)
- WPLMS와 함께 사용되는 플러그인으로, 강력한 소셜 네트워킹 및 회원 관리 기능을 제공
3. 취약점
3.1 CVE-2024-56043 [2][3]
- WPLMS의 잘못된 권한 할당으로 인한 권한 상승 취약점 (CVSS: 9.8)
영향받는 버전 : WPLMS <= 1.9.9
- includes/vibe-shortcodes/ajaxcalls.php의 wplms_register_user()에 취약점 존재
> wp_ajax_nopriv_wplms_register_user()에 의해 호출되어, 사용자 등록(≒ 회원가입)을 처리하는 함수
> Line7 : 사용자 입력인 $_POST['settings'] 값을 JSON으로 디코딩하여 $settings에 할당
> Line59 ~ Line62 : $setting 객체의 id 값을 확인해 default_role인 경우 $setting 객체의 value 값을 $user_args['role']에 할당
> Line100 : wp_insert_user($user_args)를 사용해 새로운 사용자 생성
※ WordPress의 default_role은 6가지의 값을 가짐 : Super Admin, Administrator, Editor, Author, Contributor, Subscriber [4]
- 사용자 입력으로 전달된 default_role에 대한 검증 없이 user_args['role']에 할당되므로, 임의의 역할을 지정해 권한을 상승(Super Admin, Administrator)할 수 있음
includes/vibe-shortcodes/ajaxcalls.php, function wplms_register_user()
1 function wplms_register_user(){
2 if ( !isset($_POST['security']) || !wp_verify_nonce($_POST['security'],'bp_new_signup') || !isset($_POST['settings'])){
3 echo '<div class="message">'.__('Security check Failed. Contact Administrator.','wplms').'</div>';
4 die();
5 }
6 $flag = 0;
7 $settings = json_decode(stripslashes($_POST['settings']));
8 if(empty($settings)){
9 $flag = 1;
10 }
11 ------------- CUT HERE -------------
12
13 $user_args = $user_fields = $save_settings = array();
14
15 if(empty($flag)){
16
17 ------------- CUT HERE -------------
18
19 foreach($settings as $setting){
20
21 if(!empty($setting->id)){
22 $settings2[] = $setting->id;
23 if($setting->id == 'signup_username'){
24 $user_args['user_login'] = $setting->value;
25 }else if($setting->id == 'signup_email'){
26 $user_args['user_email'] = $setting->value;
27 }else if($setting->id == 'signup_password'){
28 $user_args['user_pass'] = $setting->value;
29 }else{
30 if(strpos($setting->id,'field') !== false){
31
32 $f = explode('_',$setting->id);
33 $field_id = $f[1];
34 if(strpos($field_id, '[')){ //checkbox
35 $v = str_replace('[','',$field_id);
36 $v = str_replace(']','',$v);
37 $field_id = $v;
38 if(is_Array($user_fields[$field_id]['value'])){
39 $user_fields[$field_id]['value'][] = $setting->value;
40 }else{
41 $user_fields[$field_id] = array('value'=>array($setting->value));
42 }
43 }else{
44 if(is_numeric($field_id) && !isset($f[2])){
45 $user_fields[$field_id] = array('value'=>$setting->value);
46 }else{
47 if(in_array($f[2],array('day','month','year'))){
48 $user_fields['field_' . $field_id . '_'.$f[2]] = $setting->value;
49 }else{
50 $user_fields[$field_id]['visibility']=$setting->value;
51 }
52 }
53 }
54
55 }else{
56 if(isset($form_settings[$setting->id])){
57
58 $form_settings[$setting->id] = 0; // use it for empty check
59 if($setting->id=='default_role'){
60 $save_settings[$setting->id]=$setting->value;
61 $user_args['role'] = $setting->value;
62 }
63 if($setting->id=='member_type'){
64 $save_settings[$setting->id]=$setting->value;
65 $member_type=$setting->value;
66 }
67 if($setting->id=='wplms_user_bp_group'){
68 if(in_array($setting->value,$reg_form_settings['settings']['wplms_user_bp_group']) || $reg_form_settings['settings']['wplms_user_bp_group'] === array('enable_user_select_group')){
69 $save_settings[$setting->id]=$setting->value;
70 $wplms_user_bp_group = $setting->value;
71 }else{
72 echo '<div class="message_wrap"><div class="message error">'._x('Invalid Group selection','error message when group is not valid','wplms').'<span></span></div></div>';
73 die();
74 }
75
76 }
77 }
78
79 }
80 }
81 }
82 }
83 if(!in_array('wplms_user_bp_group', $settings2)){
84 if(!empty($reg_form_settings['settings']['wplms_user_bp_group']) && is_array($reg_form_settings['settings']['wplms_user_bp_group']) && $reg_form_settings['settings']['wplms_user_bp_group'] !== array('enable_user_select_group') && count($reg_form_settings['settings']['wplms_user_bp_group'])==1){
85 $wplms_user_bp_group = $reg_form_settings['settings']['wplms_user_bp_group'][0];
86 }
87 }
88 }
89
90 ------------- CUT HERE -------------
91
92 /*
93 FORM SETTINGS
94 */
95 if(empty($form_settings['hide_username'])){
96 $user_args['user_login'] = $user_args['user_email'];
97 }
98 $user_id = 0;
99 if(empty($form_settings['skip_mail'])){
100 $user_id = wp_insert_user($user_args);
101
102 ------------- CUT HERE -------------
3.2 CVE-2024-56048 [5][6]
- WPLMS의 권한 검증 누락으로 인한 권한 확대 취약점
영향받는 버전 : WPLMS <= 1.9.9
- include/vibe-customtypes/includes/musettings.php의 update_license_key()에 취약점 존재
> Line2 ~ Line5 : 해당 요청이 WordPress 내에서 생성된 유효한 요청인지 확인
> Line6 ~ Line9 : $_POST['addon'] 및 $_POST['key'] 값이 비어있지 않은지 확인
> Line10 : $_POST['addon'] 및 $_POST['key'] 값을 사용해 옵션 값 업데이트
- 각 값에 대한 검증이 누락되어, 권한을 확대할 수 있음
> wp_verify_nonce()에 사용되는 nonce 값은 인증된 사용자의 경우 누구나 검증 우회 가능
> $_POST['addon'] 및 $_POST['key'] 값이 비어있는지만 검증 하므로 임의의 값을 전달할 수 있음
> $_POST['addon'] 및 $_POST['key'] 값을 사용해 원하는 만큼 검증 없이 옵션 값 업데이트 가능
includes/vibe-customtypes/includes/musettings.php, function update_license_key()
1 function update_license_key(){
2 if ( !isset($_POST['security']) || !wp_verify_nonce($_POST['security'],'security')){
3 _e('Security check Failed. Contact Administrator.','wplms');
4 die();
5 }
6 if(empty($_POST['addon']) || empty($_POST['key'])){
7 _e('Unable to update key.','wplms');
8 die();
9 }
10 update_option($_POST['addon'],$_POST['key']);
11 echo apply_filters('wplms_addon_license_key_updated',__('Key Updated.','wplms'));
12 die();
13 }
3.3 CVE-2024-56040 [7][8]
- VibeBP의 잘못된 권한 할당으로 인한 권한 상승 취약점 (CVSS: 9.8)
영향받는 버전 : VibeBP <= 1.9.9.4.1
- includes/class.ajax.php의 vibebp_register_user()에 취약점 존재
> wp_ajax_nopriv_wplms_register_user()에 의해 호출되어, 사용자 등록(≒ 회원가입)을 처리하는 함수
> Line7 : 사용자 입력인 $_POST['settings'] 값을 JSON으로 디코딩하여 $settings에 할당
> Line60 ~ Line63 : $setting 객체의 id 값을 확인해 default_role인 경우 $setting 객체의 value 값을 $user_args['role']에 할당
> Line138 : wp_insert_user($user_args)를 사용해 새로운 사용자 생성
- 사용자 입력으로 전달된 default_role에 대한 검증 없이 user_args['role']에 할당되므로, 임의의 역할을 지정해 권한을 상승(Super Admin, Administrator)할 수 있음
includes/class.ajax.php, function vibebp_register_user()
1 function vibebp_register_user(){
2 if ( !isset($_POST['security']) || !wp_verify_nonce($_POST['security'],'bp_new_signup') || !isset($_POST['settings'])){
3 echo '<div class="message">'.__('Security check Failed. Contact Administrator.','wplms').'</div>';
4 die();
5 }
6 $flag = 0;
7 $settings = json_decode(stripslashes($_POST['settings']));
8 if(empty($settings)){
9 $flag = 1;
10 }
11
12 ------------- CUT HERE -------------
13
14 $user_args = $user_fields = $save_settings = array();
15
16 if(empty($flag)){
17
18 ------------- CUT HERE -------------
19
20 foreach($settings as $setting){
21
22 if(!empty($setting->id)){
23 $settings2[] = $setting->id;
24 if($setting->id == 'signup_username'){
25 $user_args['user_login'] = $setting->value;
26 }else if($setting->id == 'signup_email'){
27 $user_args['user_email'] = $setting->value;
28 }else if($setting->id == 'signup_password'){
29 $user_args['user_pass'] = $setting->value;
30 }else{
31 if(strpos($setting->id,'field') !== false){
32
33 $f = explode('_',$setting->id);
34 $field_id = $f[1];
35 if(strpos($field_id, '[')){ //checkbox
36 $v = str_replace('[','',$field_id);
37 $v = str_replace(']','',$v);
38 $field_id = $v;
39 if(is_Array($user_fields[$field_id]['value'])){
40 $user_fields[$field_id]['value'][] = $setting->value;
41 }else{
42 $user_fields[$field_id] = array('value'=>array($setting->value));
43 }
44 }else{
45 if(is_numeric($field_id) && !isset($f[2])){
46 $user_fields[$field_id] = array('value'=>$setting->value);
47 }else{
48 if(in_array($f[2],array('day','month','year'))){
49 $user_fields['field_' . $field_id . '_'.$f[2]] = $setting->value;
50 }else{
51 $user_fields[$field_id]['visibility']=$setting->value;
52 }
53 }
54 }
55
56 }else{
57 if(isset($form_settings[$setting->id])){
58
59 $form_settings[$setting->id] = 0; // use it for empty check
60 if($setting->id=='default_role'){
61 $save_settings[$setting->id]=$setting->value;
62 $user_args['role'] = $setting->value;
63 }
64 if($setting->id=='member_type'){
65 $save_settings[$setting->id]=$setting->value;
66 $member_type=$setting->value;
67 }
68 if($setting->id=='vibebp_user_bp_group'){
69 if(in_array($setting->value,$reg_form_settings['settings']['vibebp_user_bp_group']) || $reg_form_settings['settings']['vibebp_user_bp_group'] === array('enable_user_select_group')){
70 $save_settings[$setting->id]=$setting->value;
71 $vibebp_user_bp_group = $setting->value;
72 }else{
73 echo '<div class="message_wrap"><div class="message error">'._x('Invalid Group selection','error message when group is not valid','wplms').'<span></span></div></div>';
74 die();
75 }
76
77 }
78 }
79
80 }
81 }
82 }
83 }
84 if(!in_array('vibebp_user_bp_group', $settings2)){
85 if(!empty($reg_form_settings['settings']['vibebp_user_bp_group']) && is_array($reg_form_settings['settings']['vibebp_user_bp_group']) && $reg_form_settings['settings']['vibebp_user_bp_group'] !== array('enable_user_select_group') && count($reg_form_settings['settings']['vibebp_user_bp_group'])==1){
86 $vibebp_user_bp_group = $reg_form_settings['settings']['vibebp_user_bp_group'][0];
87 }
88 }
89 }
90
91
92
93 $user_args = apply_filters('vibebp_register_user_args',$user_args);
94
95
96 //hook for validations externally
97 do_action('vibebp_custom_registration_form_validations',$name,$settings,$all_form_settings,$user_args);
98 do_action('wplms_custom_registration_form_validations',$name,$settings,$all_form_settings,$user_args);
99
100 /*
101 RUN CONDITIONAL CHECKS
102 */
103 $check_filter = filter_var($user_args['user_email'], FILTER_VALIDATE_EMAIL); // PHP 5.3
104 if(empty($user_args['user_email']) || empty($user_args['user_pass']) || empty($check_filter)){
105 echo '<div class="message_wrap"><div class="message error">'._x('Invalid Email/Password !','error message when registration form is empty','wplms').'<span></span></div></div>';
106 die();
107 }
108
109 //Check if user exists
110 if(!isset($user_args['user_email']) || email_exists($user_args['user_email'])){
111 echo '<div class="message_wrap"><div class="message error">'._x('Email already registered.','error message','wplms').'<span></span></div></div>';
112 die();
113 }
114
115 //Check if user exists
116 if(!isset($user_args['user_login'])){
117
118 $user_args['user_login'] = $user_args['user_email'];
119 if(email_exists($user_args['user_login'])){
120 echo '<div class="message_wrap"><div class="message error">'._x('Username already registered.','error message','wplms').'<span></span></div></div>';
121 die();
122 }
123 }elseif (username_exists($user_args['user_login'])){
124 echo '<div class="message_wrap"><div class="message error">'._x('Username already registered.','error message','wplms').'<span></span></div></div>';
125 die();
126 }
127
128 ------------- CUT HERE -------------
129
130 /*
131 FORM SETTINGS
132 */
133 if(empty($form_settings['hide_username'])){
134 $user_args['user_login'] = $user_args['user_email'];
135 }
136 $user_id = 0;
137 if(empty($form_settings['skip_mail'])){
138 $user_id = wp_insert_user($user_args);
139
140 ------------- CUT HERE -------------
4. 대응방안
- 벤더사 제공 업데이트 적용 [9][10]
> WPLMS Plugin 1.9.9.5.3
> Vibebp 1.9.9.7.7
> 사용자가 등록할 수 있는 역할을 제한하는 패치 적용
> 추가 권한 검사를 구현하고 업데이트할 수 있는 옵션 이름에 대한 허용 목록 검사 적용
5. 참고
[1] https://patchstack.com/articles/multiple-critical-vulnerabilities-patched-in-wplms-and-vibebp-plugins/
[2] https://nvd.nist.gov/vuln/detail/CVE-2024-56043
[3] https://patchstack.com/database/wordpress/plugin/wplms-plugin/vulnerability/wordpress-wplms-plugin-1-9-9-unauthenticated-privilege-escalation-vulnerability
[4] https://developer.wordpress.org/plugins/users/roles-and-capabilities/
[5] https://nvd.nist.gov/vuln/detail/CVE-2024-56048
[6] https://patchstack.com/database/wordpress/plugin/wplms-plugin/vulnerability/wordpress-wplms-plugin-1-9-9-arbitrary-option-update-to-privilege-escalation-vulnerability
[7] https://nvd.nist.gov/vuln/detail/CVE-2024-56040
[8] https://patchstack.com/database/wordpress/plugin/vibebp/vulnerability/wordpress-vibebp-plugin-1-9-9-4-1-unauthenticated-privilege-escalation-vulnerability
[9] https://wplms.io/support/knowledge-base/vibebp-1-9-9-7-7-wplms-plugin-1-9-9-5-2/
[10] https://asec.ahnlab.com/ko/85311/
'취약점 > Elevation of Privilege' 카테고리의 다른 글
Kubernetes Image Builder 기본 자격 증명 비활성화 취약점 (CVE-2024-9486, CVE-2024-9594) (1) | 2024.10.18 |
---|---|
Ivanti 권한 상승 취약점 (CVE-2024-21888, CVE-2024-21893) (1) | 2024.02.15 |
Cisco IOS XE Software Web UI 권한 상승 취약점 (CVE-2023-20198) (1) | 2023.10.17 |
WordPress WooCommerce Payments 플러그인 권한 상승 취약점 (CVE-2023-28121) (0) | 2023.07.18 |
Microsoft Outlook 권한 상승 취약점 (CVE-2023-23397) (0) | 2023.03.21 |