
GitLab - Alta - SSRF en importación HTTPS de Gitea - eliminación del pin de UrlBlocker
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · gitlab-gitea-import-ssrf
GitLab CE 19.4.1 - GitLab Inc.
La importación de Gitea llama a UrlBlocker.validate! una vez y, luego, para https descarta la URI con la IP fijada y le entrega a Faraday el nombre de host original. UrlValidation de Octokit valida de nuevo y no reescribe env[:url]. Vuelve a enlazar el nombre entre esas búsquedas y GitLab hará GET a loopback como si fuera Gitea. El JSON de la lista de repositorios vuelve en GET /import/gitea/status.json. Las importaciones HTTP mantienen la IP fijada. https://127.0.0.1 directo está bloqueado.
Un usuario con sesión iniciada que pueda abrir la importación de Gitea en su espacio de nombres personal puede hacer que GitLab obtenga un host que él reenlaza a loopback, y recibe el cuerpo.
| ID | aún sin CVE |
| CWE | CWE-918, CWE-367 |
| CVSS | Alto: 7.7 CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N |
| Producto | GitLab CE |
| Afectado | 19.4.1-ce.0 (26212baacadb en el árbol v19.4.1-ee) |
| Autenticación | usuario autenticado, importación de Gitea, espacio de nombres personal |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | solo 127.0.0.1 |
Establece la URL del host de Gitea en https://<nombre-que-controla>/. UrlBlocker permite el primer registro A público. Los client_options de HTTPS conservan ese nombre de host. Reenlaza a 127.0.0.1. Faraday hace GET al receptor en el loopback del worker de GitLab. provider_repos de status.json es lo que haya devuelto el receptor.
En un omnibus todo-en-uno eso es Workhorse, Puma, exportadores y cualquier otra cosa que escuche en el worker. No es RCE del host. No es no autenticado. La URL de host HTTP se mantiene en la IP fijada.
Mismo producto, restos hermanos: Gitaly fetch omits resolved_address, webhook 0.0.0.0/8.
Primero leí las notas del parche del 23 de septiembre de 2026 de 19.4.1 / 19.3.3 / 19.2.7, y después el árbol v19.4.1-ee. El RCE por regex de CI, el XSS de diff de MR y la lectura de file.path de Workhorse están cerrados en esta versión. El SSRF de importación no estaba terminado.
Import::GiteaController#client_options es el resto:
host: verified_url.scheme == 'https' ? provider_url : verified_url.to_s,
HTTP usa verified_url (IP). HTTPS usa provider_url (el nombre que escribió el usuario). LegacyGithubImport::Client construye el api_endpoint de Octokit a partir de ese host. Gitlab::Octokit::UrlValidation llama a validate! y luego a @app.call(env) sin reescribir nada.
Levanté el gitlab/gitlab-ce:19.4.1-ce.0 estándar. Local-requests desactivado. CA del laboratorio en /etc/gitlab/trusted-certs porque ssl.verify de Faraday es true. DNS para gitea.lab: las búsquedas 1-2 devuelven 1.1.1.1, las búsquedas posteriores devuelven 127.0.0.1. El receptor comparte el netns de GitLab en :443. GET /import/gitea/status.json devolvió provider_repos llamado GITLAB-GITEA-IMPORT-SSRF-WITNESS. Registro del receptor: GET /api/v1/user/repos peer=127.0.0.1 host=gitea.lab.
https://127.0.0.1/ directo: "Specified URL cannot be used". http://gitea.lab/ por HTTP se mantuvo en la IP fijada y no devolvió el testigo.
Errores ya registrados: /users/sign_in con Accept: application/json da 404 (el HTML da 200); la contraseña semilla CveLabRoot9! se rechaza porque contiene root; el bind-mount de la CA en ro da EROFS después de que reconfigure enlaza el archivo; primero-dos-y-luego-loopback en la búsqueda 2 hace que UrlValidation bloquee antes de que Faraday se conecte. El modo pairs (impar público, par loopback) es el que funcionó. Una reverse shell. Teatro. El oráculo es el testigo en status.json más el peer del receptor.
cd lab
./run.sh
Objetivo solo http://127.0.0.1:18400. GitLab CE necesita varios GB de RAM. El primer arranque es lento. Solo laboratorio autorizado.
status.json status=200 ... provider_repos ... GITLAB-GITEA-IMPORT-SSRF-WITNESS
catcher GET /api/v1/user/repos peer=127.0.0.1 host=gitea.lab status=200 witness=True
negative-a https://127.0.0.1 blocked
negative-b http://gitea.lab no-witness
SUCCESS GITLAB-GITEA-IMPORT-SSRF status.json mode=pairs http=200 GITLAB-GITEA-IMPORT-SSRF-WITNESS
def client_options
verified_url, provider_hostname = verify_blocked_uri
{
host: verified_url.scheme == 'https' ? provider_url : verified_url.to_s,
api_version: 'v1',
hostname: provider_hostname
}
end
Usa verified_url.to_s para https igual que ya hace HTTP. Reescribe env[:url] en UrlValidation de Octokit a la IP fijada.
gitea_controller.rb · legacy_github_import/client.rb · octokit/url_validation.rbGNU Affero GPL v3.0. Ver LICENSE. Solo laboratorio en loopback. Sin garantía.