
Prova de conceito de laboratório demonstrando um SSRF autenticado na lista de permissões do hostmatcher do Gitea, onde um webhook para http://0.0.0.1 alcança serviços de loopback que 127.0.0.1 não consegue.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · gitea-hostmatcher-0000-ssrf
Gitea 1.27.3 - Gitea
CVE-2026-22874 adicionou reservedIPNets. CGNAT, TEST-NET, NAT64, Teredo, Azure WireServer. Faixas reais. Não o 0.0.0.0/8 da RFC 6890, o antigo bloco "this network". A IANA ainda o publica. O IsGlobalUnicast do Go é true para 0.0.0.1. Não é IsLoopback (127.0.0.0/8). Não é IsPrivate. A lista de permissões externas padrão trata-o como a internet pública. O Linux entregará 0.0.0.1 a um socket local se esse endereço estiver em lo. Mesmo listener, dois nomes.
Um usuário autenticado pode fazer webhook para http://0.0.0.1 e ler o corpo HTTP do histórico de hooks. 127.0.0.1 na mesma porta é negado.
| ID | ainda sem CVE |
| CWE | CWE-918 |
| CVSS | Alto: 7.7 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N |
| Produto | Gitea |
| Afetado | até v1.27.3 (146cc3e); resquício do CVE-2026-22874 |
| Autenticação | usuário autenticado que pode criar um webhook de repositório |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1 |
Registrar-se (registro aberto por padrão), criar um repositório, apontar um webhook para http://0.0.0.1:<local-port>/, testá-lo e ler o corpo da resposta do histórico de hooks. Isso é HTTP de loopback que 127.0.0.1 na mesma porta não consegue alcançar: qualquer coisa escutando no netns do Gitea que tenha se vinculado de forma mais ampla que o loopback, incluindo serviços que o operador pensava serem "apenas localhost" porque bloqueavam 127.0.0.0/8.
Não define X-Gitea-Internal-Auth. Não é RCE por si só. É um corpo HTTP completo de um endereço que a lista de permissões ainda chama de externo.
A v1.27.3 é a build que fechou a onda de GHSAs de 2026. Mesmo assim, fiquei nessa tag. Patches que adicionam uma lista de permissões ou uma lista de negações são um presente: você lê a lista e depois pergunta o que a IANA ainda tem que a lista esqueceu. Dois resquícios já tinham labs nesta árvore (keys IDOR e git-redirect SSRF). A tabela de resquícios naquele post listava um webhook para http://0.0.0.1/ como um mapa. Este é o SUCCESS.
A entrega de webhook armazena o corpo HTTP no histórico de hooks. Isso é um oráculo melhor que o git clone, que é basicamente "o fetch funcionou". Coloquei um oráculo no netns do Gitea na porta 8080, adicionei 0.0.0.1/8 em lo com NET_ADMIN e criei dois webhooks. Controle negativo primeiro.
Caminhos errados já registrados: tratar o HTTP 201 da criação do webhook como o oráculo (o histórico é o oráculo); a entrega para 127.0.0.1 ter sucesso (isso seria um bug diferente - o lab exige que seja negada); atingir /api/internal com X-Gitea-Internal-Auth; um reverse shell. Teatro. A testemunha é GITEA-0000-SSRF no histórico de hooks.
cd lab
./run.sh
Alvo apenas http://127.0.0.1:18131. O oráculo compartilha o netns do Gitea na porta 8080. O run.sh adiciona 0.0.0.1/8 em lo.
create-hook name=neg-loopback status=201
negative-control 127.0.0.1 blocked
create-hook name=hit-0000 status=201
poll id=2 witness=True
SUCCESS GITEA-HOSTMATCHER-0000
Adicione 0.0.0.0/8 a reservedIPNets, ou pare de tratar IsGlobalUnicast como "seguro para discar". 0.0.0.1 deve ser negado da mesma forma que 127.0.0.1 é.
hostmatcher.goGNU Affero GPL v3.0. Veja LICENSE. Apenas lab de loopback. Sem garantia.