WordPress plugin
Component name Newsletters
Vulnerable version <= 4.9.9.7
Component slug newsletters-lite
Component link https://wordpress.org/plugins/newsletters-lite/
Vulnerability class A3: Injection
Vulnerability type SQL Injection
Administrator
Newsletters 플러그인 버전 4.9.9.7 이하에서는 플러그인 대시보드(/wp-admin/admin.php?page=newsletters)에서 통계 개요 차트를 조회할 때, URL 파라미터에 대한 입력값 검증과 이스케이프 처리가 미흡하여 SQL Injection 취약점이 존재한다.
이를 통해 관리자 권한이 있는 공격자는 이 취약점을 악용하여 대상 사이트의 데이터베이스 정보를 추출할 수 있다.
뉴스레터 플러그인의 대시보드 메뉴(/wp-admin/admin.php?page=newsletters) 로 이동

브라우저 개발자 도구를 이용하여, ‘Elements’ 탭에서 action=wpmlwelcomestats&security= 를 검색하여 security 의 값을 조회

다음과 같이 나올 경우 5217e20367메모
메모한 security 값을 아래의 URL 경로의 SECURITY VALUE 부분에 입력하고 해당 URL로 요청을 보낸다.
http://localhost/wordpress/wp-admin/admin-ajax.php?action=wpmlwelcomestats&security=5217e20367=years&chart=bar&from=2024-12-31&to=2024-12-31&history_id=FOO%27+UNION+SELECT+(CONCAT((DATABASE()),%22-%22,(@@VERSION))),NULL+LIMIT+1,2+%23

하지만 나는 최신버전의 Newletter라서 안 나왔다.
위 PoC에서 SQL Injection 취약점이 발생하는 URL을 요청할 경우 /wp-content/plugins/newsletters-lite/wp-mailinglist-plugin.php 파일 내 ajax_welcomestats 함수가 호출된다.
이때, 요청 파라미터 history_id는 문자열로 이루어진 SQL 질의문의 조건절로 그대로 참조되어 변수 $history_condition으로 초기화된다.
이후 해당 변수는 아무런 이스케이프 처리 없이 데이터베이스의 질의문으로 전달된다.

따라서, URL 파라미터 history_id에 입력되는 값에 대한 검증 및 이스케이프 처리가 전혀 없어 SQL Injection 취약점이 발생한다.

$history_id = esc_html(sanitize_text_field(wp_unslash(esc_sql($_GET['history_id']))));
패치 후 코드인데 1\' OR \'1\'=\'1 이런 공격을 못하게 다층 방어(Defense in Depth) 전략을 적용한 것 같다. 왜 prepare()를 안 썼는지 모르겠다.