서버가 대신 눌러주는 버튼: SSRF 한 방이 관리자 계정을 여는 법
서버가 대신 눌러주는 버튼: SSRF 한 방이 관리자 계정을 여는 법
CVE · 웹·서버 · SSRF→계정탈취 · CVE-2026-78003 [표준]
Mailgun for WordPress 플러그인(2.2.0 이하)에서 무인증 서버측 요청 위조(SSRF)가 발견됐습니다. 흥밋점은 SSRF 자체가 아니라 그 다음입니다. 사이트가 보관한 메일 API 키로 “받은 메일 전달 규칙”을 심어, 비밀번호 재설정 메일을 가로채 관리자 계정까지 열 수 있다는 연쇄가 핵심입니다.
취약점 하나가 곧바로 치명적인 경우는 생각보다 드뭅니다. 진짜 사고는 대개 “작아 보이는 틈”이 다른 기능과 맞물려 사슬을 이룰 때 터집니다. 이번 CVE-2026-78003은 그 교과서 같은 사례입니다. 서버가 대신 요청을 보내주는 SSRF라는 흔한 결함이, 하필 “메일 전달 규칙을 만들 수 있는” 권한과 만나면서, 인증 절차의 가장 약한 고리인 비밀번호 재설정 메일을 노리는 완결된 공격으로 자랍니다. 이 글은 SSRF가 왜 단독으로도 위험하지만, 특히 계정 탈취로 이어지는 다리가 무엇인지를 짚습니다.
01 · 개요
CVE-2026-78003은 WordPress용 “Mailgun for WordPress” 플러그인 2.2.0 이하 버전에 존재하는 서버측 요청 위조(SSRF, Server-Side Request Forgery) 취약점입니다. 인증이 필요 없습니다. 공격자는 로그인하지 않은 상태로, 사이트가 이미 보관 중인 Mailgun API 키를 사용해 임의의 Mailgun API 엔드포인트로 요청을 보내게 만들 수 있습니다.
가장 위험한 활용은 “받은 메일 전달(inbound routes)” 규칙을 만드는 것입니다. 이 규칙으로 비밀번호 재설정 메일을 공격자에게 흘리면, 관리자 계정 탈취까지 이어집니다. 심각도는 CVSS 3.1 기준 9.8(치명적), 벡터는 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H로 평가됐습니다(취약점 분류 CWE-918, SSRF). 즉 원격에서, 낮은 난이도로, 아무 권한 없이, 사용자 상호작용 없이 기밀성·무결성·가용성을 모두 무너뜨릴 수 있다는 뜻입니다.
한 줄 요약 — “서버가 나 대신 인증된 요청을 보내준다”는 SSRF의 본질이, 메일 전달 규칙 조작과 만나 관리자 계정을 여는 열쇠가 됐습니다.
02 · 기술 배경
SSRF(서버측 요청 위조) 는 공격자가 직접 갈 수 없는 곳으로 서버가 대신 요청을 보내게 만드는 결함입니다. 요청의 출발지가 신뢰받는 서버이기 때문에, 서버만 접근할 수 있는 내부 자원이나 서버가 쥐고 있는 인증 정보(API 키 등)를 그대로 빌려 쓰게 되는 것이 위험의 핵심입니다.
이번 사례에서 서버가 쥔 인증 정보는 Mailgun API 키입니다. Mailgun은 메일 발송·수신을 대행하는 외부 서비스이고, 플러그인은 사이트를 대신해 이 API를 호출하려고 키를 저장해 둡니다. 여기서 SSRF가 나면, 공격자는 자기 손에 없는 이 키로 인증된 API 호출을 유도할 수 있습니다.
또 하나 알아둘 개념이 경로 순회(path traversal) 입니다. 사용자가 넣은 값이 URL 경로의 일부로 이어 붙을 때, ../ 같은 조각이나 예상 밖의 경로 조각을 끼워 넣어 원래 의도한 위치가 아닌 다른 엔드포인트로 요청을 돌리는 기법입니다. NVD 설명에 따르면 이번 취약점은 SSRF가 바로 이 경로 순회를 통해 발생합니다.
03 · CVE 분석 요약
NVD 설명에 명시된 사실만 정리하면 다음과 같습니다.
- 원인이 되는 함수는
add_list()입니다. - 이 함수는
$_POST['addresses']에서 사용자가 통제하는 배열 키(array key) 를 받아들입니다. - 받은 값을
sanitize_text_field()로 통과시키지만, 이 정도의 처리로는 충분한 입력 검증이 되지 않습니다(insufficient input validation). - 그 결과, 이 값이 경로 순회를 통해 요청 경로에 끼어들어, 사이트의 Mailgun API 키로 임의의 Mailgun API 엔드포인트를 호출하는 인증된 POST 요청이 만들어집니다.
핵심을 개념으로 풀면 이렇습니다. sanitize_text_field() 는 WordPress에서 흔히 쓰는 문자열 정리 함수로, 태그를 제거하고 공백을 다듬는 정도의 “일반 텍스트 위생 처리”를 합니다. 하지만 이 값이 API 요청 경로의 일부로 쓰인다면 그 맥락에 맞는 검증(허용된 엔드포인트인지, 경로를 벗어나지 않는지)이 필요합니다. 값을 “표시할 텍스트”로만 취급하고 “요청 대상 경로”로는 검증하지 않은 것 — 이 맥락 불일치가 빈틈으로 보입니다(추정: 정확한 코드 흐름은 아래 캡션 참고).
// 개념용 단순화 — 실제 소스/페이로드 아님
// 사용자가 넣은 배열 키가 API 요청 경로로 그대로 흘러가는 구조를 개념화한 것
$keys = array_keys( $_POST['addresses'] ); // 사용자가 키를 통제
foreach ( $keys as $key ) {
$part = sanitize_text_field( $key ); // 텍스트 위생 처리는 하지만
$endpoint = MAILGUN_API . '/' . $part; // 경로 검증 없이 API 경로에 결합
call_mailgun_api( $endpoint, $api_key ); // 사이트 API 키로 인증 호출
}
위 코드는 원인 구조를 이해하기 위한 개념용 단순화이며, 실제 플러그인 소스나 동작하는 페이로드가 아닙니다. 실제 함수 위치는 공식 저장소 mailgun.php의 add_list() 부근(References 참고).
정리하면 흐름은 “사용자 통제 입력 → 불충분한 검증 → 경로 순회로 임의 API 엔드포인트 지정 → 사이트 키로 인증된 호출” 입니다. 이 마지막 단계, 즉 “사이트 키로 인증된 호출”이 만들어진다는 점이 다음 절의 계정 탈취 연쇄를 가능하게 하는 지렛대입니다.
04 · 왜 SSRF가 계정 탈취까지 가는가 (우리 논평)
SSRF는 흔히 “내부망 스캔”이나 “메타데이터 서버 조회” 정도로만 이해되곤 합니다. 하지만 이번 사례가 보여주는 더 중요한 교훈은 SSRF가 ‘서버의 신원을 빌려 쓰는’ 결함이라는 점입니다. 서버가 보내는 요청은 서버의 자격(여기서는 Mailgun API 키)을 달고 나갑니다. 공격자에게 없는 자격을 서버가 대신 실어 보내주는 것 — 이것이 SSRF의 진짜 파괴력입니다.
그래서 연쇄가 성립합니다.
- SSRF로 인증된 API 호출을 얻는다. 공격자는 키가 없지만, 서버가 키를 실어 보내준다.
- 그 API로 “받은 메일 전달 규칙”을 만든다. NVD 설명이 짚은 대로, 임의 엔드포인트 호출이 가능하므로 inbound 라우팅 생성도 가능하다.
- 비밀번호 재설정 메일을 가로챈다. 관리자 계정으로 비밀번호 찾기를 요청하면, 재설정 링크가 담긴 메일이 공격자에게 전달된다.
- 재설정 링크로 관리자 계정을 장악한다.
이 사슬의 급소는 비밀번호 재설정이라는 절차 자체가 “메일함 통제 = 계정 통제”라는 전제 위에 서 있다는 점입니다. 인증의 최종 안전장치를 메일 채널에 맡겨 둔 시스템에서, 메일 흐름을 조작할 수 있는 능력은 곧 인증 우회 능력이 됩니다. 이 관점은 우리가 다뤄온 다른 계열과 뿌리가 같습니다 — 인증우회는 로그인 로직만의 문제가 아니라, 인증이 의존하는 부속 채널(메일·세션·토큰 발급)의 신뢰를 깨는 문제라는 것입니다(내부 글: 인증우회·계정탈취 연쇄 계열, 크로스클래스 취약점 추론).
한 가지 더. 이 취약점은 “입력을 씻긴 했다(sanitize_text_field)“는 점에서 특히 교훈적입니다. 위생 처리를 했다는 사실이 곧 안전을 뜻하지 않습니다. 값이 쓰이는 맥락(표시용 텍스트냐, 요청 경로냐, 쿼리 인자냐)마다 필요한 검증이 다르기 때문입니다. 맥락을 무시한 획일적 sanitize는 반복되는 실패 패턴입니다.
05 · 공격 시나리오 · 영향도 + 대응방안
공격 시나리오 (단계 개념만)
- 공격자가 무인증 상태로 취약한 엔드포인트에 조작된
addresses입력을 담은 POST 요청을 보낸다. - 불충분한 검증을 지나 경로 순회로 요청이 원치 않는 Mailgun API 엔드포인트로 향하고, 서버가 사이트 키로 인증된 호출을 대행한다.
- 이를 이용해 받은 메일 전달 규칙을 심고, 관리자 비밀번호 재설정 메일을 자신에게 흘려 계정을 넘겨받는다.
완성형 익스플로잇·작동 페이로드는 싣지 않습니다(랩 공개 윤리 + 저작권). 위는 원리 이해를 위한 단계 개념일 뿐입니다.
영향도
- 무인증·원격·저난이도로 관리자 계정 탈취까지 이어질 수 있는 연쇄. CVSS 9.8(치명적), CWE-918.
- 관리자 장악은 사실상 사이트 전체 장악(콘텐츠 변조, 악성 코드 삽입, 데이터 유출 등으로 확대될 수 있음 — 예상되는 후속 영향).
대응방안 (1급 요소)
- 근본 — 2.2.1 이상으로 업데이트. 이 취약점은 2.2.1에서 패치됐습니다(2026-07-09,
add_listAJAX 액션에 nonce 검증 + 서버측 주소 검증 추가). 현재 배포 최신판은 2.2.2(2026-07-17, 별개 보안수정 포함)이므로 최신판으로 즉시 업데이트하는 것을 권고합니다. 2.2.0 이하는 전부 취약합니다. - 차선 (즉시 업데이트가 불가할 때):
- 패치 적용 전까지 플러그인을 일시 비활성화하는 것을 우선 검토.
- 웹 방화벽(WAF)에서 해당 엔드포인트로 향하는
addresses파라미터의 이상 입력(경로 순회 조각 등)을 차단하는 규칙 적용. - 노출된 것으로 판단되면 Mailgun API 키를 폐기·재발급하고, 이미 생성됐을 수 있는 비정상 inbound 메일 전달(routes) 규칙을 점검·제거.
- 관리자 계정 비밀번호 변경 및 가능하면 다중 인증(2FA) 을 켜, 메일 채널 하나에만 의존하지 않도록 인증을 이중화.
- 탐지 관점: Mailgun 대시보드/로그에서 최근 생성된 낯선 inbound route가 있는지, 관리자 비밀번호 재설정 메일이 예상치 못한 주소로 나간 흔적이 있는지 확인. 취약 엔드포인트로 향한 무인증 POST 급증 로그도 신호입니다.
06 · 결론
핵심: SSRF의 진짜 위험은 “서버의 신원을 빌려 쓴다”는 데 있고, 그 신원이 메일 채널을 통제할 수 있을 때 인증의 최종 안전장치가 무너집니다.
이런 부류가 반복되는 이유는 단순합니다. 개발자는 값을 “씻겼는지”에 집중하지만, 공격자는 값이 “어디로 흘러 무엇이 되는지”를 봅니다. 한 번의 위생 처리로 모든 맥락을 막을 수 있다는 착각이 SSRF·경로 순회·주입 계열을 계속 되살립니다.
이번 한 틈은 패치로 닫히겠지만, “부속 채널(메일)의 신뢰를 깨서 인증을 우회한다”는 사고방식은 다른 자리에서 또 나타납니다. 그래서 우리는 이 CVE 하나의 재현 절차가 아니라, 연쇄를 읽는 방법을 남깁니다.
References / 참고자료
- Wordfence, “Mailgun for WordPress ≤ 2.2.0 — Unauthenticated SSRF via Path Traversal (CVE-2026-78003)” — 이 글이 재구성한 원 분석(1차 advisory). 취약 함수·연쇄·심각도의 근거. 발견자: Osvaldo Noe Gonzalez Del Rio(Os). https://www.wordfence.com/threat-intel/vulnerabilities/id/110e888d-69fc-4682-b908-2b62288c5227?source=cve
- NVD, “CVE-2026-78003” — CVSS 3.1 9.8(
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), CWE-918, 취약 버전(≤2.2.0)·설명 등재(2026-08-22). https://nvd.nist.gov/vuln/detail/CVE-2026-78003 - WordPress Plugin Repository,
mailgun.php(tag 2.1.10) —add_list()함수 소스 위치 참고(개념 분석의 근거, 라인 L259~557 부근). https://plugins.trac.wordpress.org/browser/mailgun/tags/2.1.10/mailgun.php - OWASP, “Server-Side Request Forgery (SSRF)” / CWE-918 — SSRF 개념·방어 원칙 배경 자료.
이 글은 위 원 분석을 우리 관점에서 다시 쓰고 논평을 더한 것입니다. 특정 문장·코드를 그대로 옮기지 않았으며, 자세한 재현 절차는 원문을 참고하세요.