오늘은 ! WordPress Plugin의 Bookit 취약점에 대해 공부해보려한다.
CVE-2023-2384에 대해 알아보자. 취약점 분석 글이 자세하게 적혀있어 차근차근 따라가며 학습해보려고 한다.
Wordpress Bookit 2.3.6 이하 버전에서 발생하는 인증 우회 취약점. 사용자의 Email만 알고 있다면, 해당 사용자로 로그인할 수 있다.
바로 코드부터 살펴보자. 취약한 코드는 CustomerController.php 파일에 존재한다.
public static function get_customer( $data ) {
if ( ! empty( $data['user_id'] ) ) {
$id = Customers::get('wp_user_id', $data['user_id'])->id;
} else {
$id = Customers::get('email', $data['email'])->id;
}
IF 조건문을 통해 user_id가 있는지 없는지 확인한다.
만약 user_id가 있다면, user_id를 통해서 id를 가져오고, user_id가 없다면, E-mail을 통해 id를 가져온다.
$data는 사용자가 입력한 파라미터이다.
다음 코드를 살펴보자.
$settings = SettingsController::get_settings();
if ( $settings['booking_type'] == 'registered' && !is_user_logged_in() ) {
$data['role'] = User::$customer_role;
$data['user_id'] = Customers::save_or_get_wp_user($data);
/** Authorize wp User */
wp_clear_auth_cookie();
wp_set_current_user ( $data['user_id'] );
wp_set_auth_cookie ( $data['user_id'] );
}
위에서 get_settings()를 통해 설정을 가져온다.
이를 통해 booking_type이 예약된 상태이고, 사용자가 로그인되지 않은 상태라면 아래의 로직으로 이동하게 된다.
아래의 로직은 save_or_get_wp_user 메서드를 통해 user_id를 가져온다.
참고용으로 save_or_get_wp_user 함수를 가져와봤다.
public static function save_or_get_wp_user($data) {
$is_exist_user = get_user_by_email($data['email']);
if ( $is_exist_user ) {
return $is_exist_user->data->ID;
}
$user_data = [
'user_login' => $data['email'],
'user_pass' => $data['password'],
'first_name' => $data['full_name'],
'last_name' => '',
'user_email' => $data['email']
];
if ( empty( $user_data['first_name'] ) ) {
$user_data['first_name'] = $data['email'];
}
if ( array_key_exists('role', $data) && get_role($data['role']) != null ) {
$user_data['role'] = $data['role'];
}
return wp_insert_user($user_data);
}
다시 계속해서 살펴보자.
$settings = SettingsController::get_settings();
if ( $settings['booking_type'] == 'registered' && !is_user_logged_in() ) {
$data['role'] = User::$customer_role;
$data['user_id'] = Customers::save_or_get_wp_user($data);
/** Authorize wp User */
wp_clear_auth_cookie();
wp_set_current_user ( $data['user_id'] );
wp_set_auth_cookie ( $data['user_id'] );
}
wp_clear_auth_cookie 함수를 통해 Cookie를 clear 시키고,
찾은 user_id를 통해 wp_set_current_user와 wp_set_auth_cookie를 설정한다.
wp_set_current_user 함수는 user_id를 통해 현재 사용자를 변경하는 함수이고, wp_set_auth_cookie 함수는 사용자 ID를 기반으로 쿠키를 설정하는 함수이다.
궁금하다면, 아래의 링크를 통해 확인해볼 수 있다.
✔️ wp_set_current_user() - https://developer.wordpress.org/reference/functions/wp_set_current_user/
✔️ wp_set_auth_cookie() - https://developer.wordpress.org/reference/functions/wp_set_auth_cookie/
즉, 예약할 때 존재하는 ID의 E-mail을 잘 입력해주면 해당 ID로 로그인할 수 있다.
그러면 위의 내용 토대로 실제 취약한 버전을 다운로드하여 구현해보자.
[bookit]
위의 ShortCode를 통해 페이지를 생성해준다.
생성 후 카테고리를 하나 생성해주고 서비스를 생성하고 마지막으로 Staff도 하나 생성해줘야한다.
위의 카테고리, 서비스, 직원을 생성해주면 캘린더를 통해 예약을 할 수 있다.
"SUBMIT" 버튼을 클릭해준다.
다른 부분을 모두 채워준다. 중요한 부분은 E-mail 입력란에 관리자 E-mail을 입력하여 BOOK NOW 버튼을 눌러준다.
관리자 계정으로 로그인되는 것을 확인할 수 있다.(coco가 관리자 계정 닉네임)
끝 🥳