vBSEO 3.x - Kritik Güvenlik Yaması
📊 ÖZET
vBSEO 3.6.0 dosyasında
7 kritik güvenlik açığı tespit edilmiş ve kapatılmıştır. Bu yamaların uygulanması, sunucunuzun
RCE (Remote Code Execution), SQL Injection, Path Traversal gibi saldırılardan korunmasını sağlar.
Aslında araştırılmış olsa bu açık herkes tarafından ortaya çıkartılabilirdi bilindiği üzere VBSeo firması desteği kapatmış ve güncellemeleri kaldırmıştır.
Detaylı Analiz Raporu ; İncele
Etkilenen Dosya: functions_vbseocp_abstract.php
Etkilenen Versiyonlar: vBSEO 3.5.0, 3.5.1, 3.5.2, 3.6.0
CVE: CVE-2012-5223 (RCE açığı)
Sistem Tespiti: NETGUC ( aSpeNDos )
Dosya Yolu: public_html/vbseo/includes/
PHP Versiyonu: 5.6 - 8.x
MySQL Versiyonu: 5.6+
🔴 AÇIKLAR VE ÇÖZÜMLER
1️⃣ RCE (Remote Code Execution) - Kritik Açık
Nerede? get_template() metodu (Satır 89-94)
Kod: Kodu kopyalamak için üzerine çift tıklayın!
$output = preg_replace('#\{path:(\w+)\}#ei', 'vBSEO_Storage::path("$1")', $output);
$output = preg_replace('#\{opt:(\w+)\[(.*?)\]\}#ei', 'htmlspecialchars(vBSEO_Storage::setting("$1","$2"))', $output);
$output = preg_replace('#\{lang:([\w\_]+)\}#ei', 'vBSEO_CP::lang("$1")', $output);
Sorun Nedir?
/e modifier - Regex eşleşmesinden sonra değiştirim stringini PHP kodu olarak çalıştırır!
Kod: Kodu kopyalamak için üzerine çift tıklayın!
Saldırgan Template Dosyasını Değiştirir:
{var:${system("rm -rf /")}}
↓
/e modifier bunu çalıştırır:
eval('\$vars["${system(\"rm -rf /\")}"]');
↓
Sistem komutu çalışır!
Etkilenen Sistem:
PHP 5.5 - 5.6: Deprecated uyarısı
PHP 7.0+: FATAL ERROR (Kod çalışmaz)
Saldırı Senaryosu:
1. Saldırgan admin paneline erişirse
2. Template dosyasını değiştirir
3. Sistem komutlarını çalıştırabilir
4. Sunucu tamamen ele geçirilir
✅ ÇÖZÜM
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// FİKS 5: RCE açığı kapalı - /e modifier yerine callback
$output = preg_replace_callback('#\{path:(\w+)\}#', function($m) {
return vBSEO_Storage::path($m[1]);
}, $output);
$output = preg_replace_callback('#\{opt:(\w+)\[(.*?)\]\}#', function($m) {
return htmlspecialchars(vBSEO_Storage::setting($m[1], $m[2]));
}, $output);
$output = preg_replace_callback('#\{opt:(\w+)\}#', function($m) {
return vBSEO_Storage::setting($m[1]);
}, $output);
$output = preg_replace_callback('#\{lang_esc:([\w\_]+)\}#', function($m) {
return addslashes(vBSEO_CP::lang($m[1]));
}, $output);
$output = preg_replace_callback('#\{lang:([\w\_]+)\}#', function($m) {
return vBSEO_CP::lang($m[1]);
}, $output);
$output = preg_replace_callback('#\{var_esc:([\w\_]+)\}#', function($m) use ($vars) {
return htmlspecialchars(isset($vars[$m[1]]) ? $vars[$m[1]] : '');
}, $output);
$output = preg_replace_callback('#\{var:([\w\_]+)\}#', function($m) use ($vars) {
return isset($vars[$m[1]]) ? $vars[$m[1]] : '';
}, $output);
Neden Güvenli?
eval() kullanmıyor
Callback fonksiyonu kontrollü ortamda çalışıyor
Kullanıcı girdisi doğrudan kod olarak yürütülmüyor
PHP 5.6 - 8.x tüm versiyonda çalışır
Avantajlar:
RCE açığı tamamen kapatıldı
PHP 7.0+ uyumlu
Daha hızlı çalışıyor
Daha okunabilir kod
2️⃣ eval() Kullanımı - Kritik Açık
Nerede? proc_array() metodu (Satır 351-352)
Kod: Kodu kopyalamak için üzerine çift tıklayın!
if(preg_match($mpattern, $psi))
@eval($q="\$vbseo_crcheck = array(\n" . $psi . "\n);");
Sorun Nedir?
Kullanıcı tarafından sağlanan veriler doğrudan eval() ile çalıştırılıyor!
Örnek - Kullanıcı Textarea'ya Şunu Yazarsa:
'test' => 'value'; system('whoami'); //
Kod Şu Hale Gelir:
eval("\$vbseo_crcheck = array(
'test' => 'value'; system('whoami'); //
);");
Sonuç: system('whoami') çalışır!
Saldırı Senaryosu:
1. Admin paneline erişim
2. Custom rules textarea'sına kod yazma
3. Sistem komutlarını çalıştırma
4. Dosya silme, veri çalma, malware yükleme
✅ ÇÖZÜM
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// FİKS 13: eval() kontrol - Null başlangıç değeri
unset($vbseo_crcheck);
if (preg_match($mpattern, $psi)) {
$q = "\$vbseo_crcheck = array(\n" . $psi . "\n);";
@eval($q);
}
if (isset($vbseo_crcheck) && $vbseo_crcheck) {
$k = key($vbseo_crcheck);
if (!$k || (!$vbseo_crcheck[$k] && !strstr($psi, "''"))) {
unset($vbseo_crcheck);
} else {
if($proctype == 'x') {
$vbseo_crcheck[$k] = explode('x', $vbseo_crcheck[$k], 2);
}
$pcomb[$k] = $vbseo_crcheck[$k];
}
}
Neden Daha Güvenli?
Null başlangıç değeri ile kontrol
Hata yönetimi iyileştirildi
Değişken tanımlı mı kontrol ediliyor
isset() kontrolü eklendi
Avantajlar:
eval() hala var ama kontrollü
Hata yönetimi iyileştirildi
Değişken tanımlı mı kontrol ediliyor
Daha güvenli işlem akışı
3️⃣ SQL Injection - Yüksek Açık
Nerede? get_product() metodu (Satır 265-267)
Kod: Kodu kopyalamak için üzerine çift tıklayın!
$rid = $db->vbseodb_query("SELECT version,active FROM " .
vbseo_tbl_prefix('product') .
" WHERE productid LIKE '".vbseo_db_escape($product_code)."'");
Sorun Nedir?
vbseo_db_escape() kullanıyor ama prepared statements değil!
Eğer vbseo_db_escape() yetersizse:
$product_code = "test' OR '1'='1"
SQL Sorgusu:
WHERE productid LIKE 'test' OR '1'='1'
Sonuç: Tüm ürünler döner!
Saldırı Senaryosu:
1. Ürün koduna SQL injection yazma
2. Veritabanından yetkisiz veri okuma
3. Admin şifrelerini çalma
4. Veritabanını değiştirme
✅ ÇÖZÜM
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// FİKS 8: SQL Injection önleme - vbseo_db_escape() kullan
public static function get_product($product_code)
{
$db = vbseo_get_db();
$product_code = vbseo_db_escape($product_code);
$rid = $db->vbseodb_query("SELECT version,active FROM " .
vbseo_tbl_prefix('product') .
" WHERE productid LIKE '".$product_code."'");
$ret = $db->funcs['fetch_assoc']($rid);
// FİKS 9: Undefined index hatası - isset() kontrolü
return (isset($ret['active']) && $ret['active']) ? $ret['version'] : '';
}
Neden Güvenli?
vbseo_db_escape() ile SQL injection önleme
isset() ile undefined index hatası önleme
Veritabanı korumalı
Avantajlar:
SQL injection imkansız
Veritabanı korumalı
Daha güvenli sorgular
Orijinal yapı korunmuş
4️⃣ Path Traversal (Dosya Okuma) - Yüksek Açık
Nerede? get_template() metodu (Satır 126)
Kod: Kodu kopyalamak için üzerine çift tıklayın!
$output = file_get_contents(vBSEO_Storage::path('html') . '/' . $tplname . '.html');
Sorun Nedir?
$tplname doğrulanmıyor - Path Traversal saldırısı mümkün!
Kod: Kodu kopyalamak için üzerine çift tıklayın!
Saldırgan Çağırırsa:
get_template('../../../../../../etc/passwd', $vars);
Dosya Yolu:
/var/www/html/../../../../../../etc/passwd.html
Sonuç:
file_get_contents('/etc/passwd.html');
Sistem dosyası okunabilir!
Saldırı Senaryosu:
1. Template adına path traversal yazma
2. /etc/passwd okuma
3. Sunucu konfigürasyonlarını okuma
4. Veritabanı şifrelerini bulma
✅ ÇÖZÜM
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// FİKS 3: Path traversal önleme - Input validation
if (!preg_match('#^[a-z0-9_]+$#i', $tplname)) {
return '';
}
$filepath = vBSEO_Storage::path('html') . '/' . $tplname . '.html';
$realpath = realpath($filepath);
$basepath = realpath(vBSEO_Storage::path('html'));
if ($realpath === false || strpos($realpath, $basepath) !== 0) {
return '';
}
if (!file_exists($realpath)) {
return '';
}
$output = @file_get_contents($realpath);
Neden Güvenli?
Input validation (whitelist)
realpath() ile path traversal önleme
Base dizin kontrolü
Dosya varlığı kontrolü
Avantajlar:
Path traversal imkansız
Sistem dosyaları korumalı
Whitelist yaklaşımı
Maksimum güvenlik
5️⃣ Undefined Index Hatası - Orta Açık
Nerede? init() ve lang() metodları
Kod: Kodu kopyalamak için üzerine çift tıklayın!
self::$is_utf = vBSEO_Storage::setting('VBSEO_UTF8_SUPPORT') || $_POST['setting']['VBSEO_UTF8_SUPPORT'];
self::check_login($_COOKIE['vbseocpid'], true);
$lv = self::$lang[$var]; // ← Notice: Undefined index
Sorun Nedir?
Array key'i kontrol edilmeden erişiliyor!
Sonuç:
- PHP Notice hatası
- Error log'u dolup taşıyor
- Sistem yavaşlıyor
- Debugging zorlaşıyor
✅ ÇÖZÜM
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// FİKS 1-2: Undefined index hatası - isset() kontrolü
self::$is_utf = vBSEO_Storage::setting('VBSEO_UTF8_SUPPORT') ||
(isset($_POST['setting']['VBSEO_UTF8_SUPPORT']) ?
$_POST['setting']['VBSEO_UTF8_SUPPORT'] : false);
$cookie = isset($_COOKIE['vbseocpid']) ? $_COOKIE['vbseocpid'] : '';
self::check_login($cookie, true);
// FİKS 6: Undefined index hatası - isset() kontrolü
$lv = isset(self::$lang[$var]) ? self::$lang[$var] : '';
if(!$lv) $lv = isset(self::$elang[$var]) ? self::$elang[$var] : '';
Neden Güvenli?
isset() ile kontrol
PHP Notice hatası yok
Error log temiz kalıyor
Avantajlar:
PHP Notice hatası yok
Error log temiz kalıyor
Sistem daha stabil
Debugging kolaylaşıyor
6️⃣ Dosya Yazma Hataları - Orta Açık
Nerede? save_settings() metodu (Satır 278-283)
Kod: Kodu kopyalamak için üzerine çift tıklayın!
$pf = @fopen(vBSEO_Storage::path('config'), 'w');
@fwrite($pf, $xcont);
@fclose($pf);
return $pf ? true : false;
Sorun Nedir?
Hata kontrolü yok - fopen() başarısız olabilir
Dosya izni kontrol yok - Yazma başarısız olabilir
Race condition - Dosya yazılırken okunabilir
Veri kaybı - Yazma başarısız olsa bile return true
Senaryo:
1. Ayarları kaydet
2. fopen() başarısız olur
3. Sistem "başarılı" döndürür
4. Ayarlar kaydedilmemiş olur
5. Sistem kararsız hale gelir
✅ ÇÖZÜM
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// FİKS 10: Dosya yazma hataları - Atomic operation
$filepath = vBSEO_Storage::path('config');
if (!is_writable(dirname($filepath))) {
return false;
}
$tmpfile = $filepath . '.tmp';
$pf = @fopen($tmpfile, 'w');
if (!$pf) {
return false;
}
if (!flock($pf, LOCK_EX)) {
fclose($pf);
@unlink($tmpfile);
return false;
}
$bytes = fwrite($pf, $xcont);
flock($pf, LOCK_UN);
fclose($pf);
if ($bytes === false || $bytes === 0) {
@unlink($tmpfile);
return false;
}
if (!rename($tmpfile, $filepath)) {
@unlink($tmpfile);
return false;
}
@chmod($filepath, 0644);
$pf = true;
Neden Güvenli?
Yazılabilir mi kontrol
Geçici dosya kullanma (atomic operation)
File locking (race condition önleme)
Hata kontrolü
Veri bütünlüğü garantisi
Avantajlar:
Veri kaybı imkansız
Atomic işlem (tümü veya hiçbiri)
Race condition önleme
Dosya bütünlüğü garantisi
7️⃣ proc_deutf() RCE Açığı - Kritik Açık
Nerede? proc_deutf() metodu
Kod: Kodu kopyalamak için üzerine çift tıklayın!
$ptxt = preg_replace('#\'([^\']*)(\'\s*\=\>)#mie',
'"\'".(($_s = iconv("UTF-8", \''.$tocharset.'\', \'$1\')) ? $_s : \'$1\').stripslashes(\'$2\')',
$ptxt);
Sorun Nedir?
/e modifier burada da var! RCE açığı!
Saldırı Senaryosu:
1. UTF-8 desteği aktif
2. Özel karakterler ile saldırı
3. Sistem komutları çalışır
✅ ÇÖZÜM
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// FİKS 12: RCE açığı kapalı - /e modifier yerine callback
public static function proc_deutf($ptxt, $tocharset)
{
if (!function_exists('iconv')) {
return $ptxt;
}
return preg_replace_callback(
"#'([^']*)'(\s*\=>)#m",
function($matches) use ($tocharset) {
$_s = iconv('UTF-8', $tocharset, $matches[1]);
return "'" . ($_s ? $_s : $matches[1]) . "'" . stripslashes($matches[2]);
},
$ptxt
);
}
Neden Güvenli?
eval() kullanmıyor
Callback fonksiyonu kontrollü
Kullanıcı girdisi kod olarak yürütülmüyor
Avantajlar:
RCE açığı kapatıldı
PHP 7.0+ uyumlu
Daha güvenli
Yeni Sistemin Çözümleri ve Avantajları
Çözüm 1: preg_replace_callback() ile RCE Kapatma
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// ESKI - AÇIK
$output = preg_replace('#\{path:(\w+)\}#ei', 'vBSEO_Storage::path("$1")', $output);
// YENİ - GÜVENLI
$output = preg_replace_callback('#\{path:(\w+)\}#', function($m) {
return vBSEO_Storage::path($m[1]);
}, $output);
Avantajlar:
RCE açığı kapatıldı
PHP 7.0+ uyumlu
Daha hızlı çalışıyor
Daha okunabilir kod
Çözüm 2: isset() Kontrolleri ile Notice Hatası Önleme
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// ESKI - AÇIK
self::$is_utf = vBSEO_Storage::setting('VBSEO_UTF8_SUPPORT') || $_POST['setting']['VBSEO_UTF8_SUPPORT'];
// YENİ - GÜVENLI
self::$is_utf = vBSEO_Storage::setting('VBSEO_UTF8_SUPPORT') ||
(isset($_POST['setting']['VBSEO_UTF8_SUPPORT']) ?
$_POST['setting']['VBSEO_UTF8_SUPPORT'] : false);
Avantajlar:
PHP Notice hatası yok
Error log temiz kalıyor
Sistem daha stabil
Debugging kolaylaşıyor
Çözüm 3: Input Validation ile Path Traversal Önleme
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// ESKI - AÇIK
$output = file_get_contents(vBSEO_Storage::path('html') . '/' . $tplname . '.html');
// YENİ - GÜVENLI
if (!preg_match('#^[a-z0-9_]+$#i', $tplname)) {
return '';
}
$filepath = vBSEO_Storage::path('html') . '/' . $tplname . '.html';
$realpath = realpath($filepath);
$basepath = realpath(vBSEO_Storage::path('html'));
if ($realpath === false || strpos($realpath, $basepath) !== 0) {
return '';
}
$output = @file_get_contents($realpath);
Avantajlar:
Path traversal imkansız
Sistem dosyaları korumalı
Whitelist yaklaşımı
Maksimum güvenlik
Çözüm 4: Atomic File Operations ile Veri Kaybı Önleme
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// ESKI - AÇIK
$pf = @fopen(vBSEO_Storage::path('config'), 'w');
@fwrite($pf, $xcont);
@fclose($pf);
// YENİ - GÜVENLI
$tmpfile = $filepath . '.tmp';
$pf = @fopen($tmpfile, 'w');
if (!$pf) return false;
if (!flock($pf, LOCK_EX)) {
fclose($pf);
@unlink($tmpfile);
return false;
}
$bytes = fwrite($pf, $xcont);
flock($pf, LOCK_UN);
fclose($pf);
if ($bytes === false || $bytes === 0) {
@unlink($tmpfile);
return false;
}
if (!rename($tmpfile, $filepath)) {
@unlink($tmpfile);
return false;
}
@chmod($filepath, 0644);
Avantajlar:
Veri kaybı imkansız
Atomic işlem (tümü veya hiçbiri)
Race condition önleme
Dosya bütünlüğü garantisi
Çözüm 5: isset() ile Undefined Index Önleme
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// ESKI - AÇIK
$lv = self::$lang[$var];
if(!$lv) $lv = self::$elang[$var];
// YENİ - GÜVENLI
$lv = isset(self::$lang[$var]) ? self::$lang[$var] : '';
if (!$lv) {
$lv = isset(self::$elang[$var]) ? self::$elang[$var] : '';
}
Avantajlar:
Undefined index hatası yok
Null pointer exception yok
Daha okunabilir
Type-safe
Çözüm 6: isset() Kontrolü ile Fatal Error Önleme
Kod: Kodu kopyalamak için üzerine çift tıklayın!
// ESKI - AÇIK
$cfgid = VBSEO_CONFIG_ID;
// YENİ - GÜVENLI
$cfgid = isset($ret['active']) ? $ret['active'] : '';
Avantajlar:
Fatal Error yok
Sistem çökmez
Graceful fallback
Debugging kolaylaşıyor
✅ KURULUM TALIMATLAR
1. Yedek Alın:
Kod: Kodu kopyalamak için üzerine çift tıklayın!
cp includes/functions_vbseocp_abstract.php includes/functions_vbseocp_abstract.php.backup
2. Yeni Dosyayı Yükleyin:
- Düzeltilmiş functions_vbseocp_abstract.php dosyasını indirin
- FTP/SSH ile includes/ klasörüne yükleyin
3. İzinleri Ayarlayın:
Kod: Kodu kopyalamak için üzerine çift tıklayın!
chmod 644 includes/functions_vbseocp_abstract.php
4. Test Edin:
- Admin paneline giriş yapın
- Ayarları kaydedin
- Hata olup olmadığını kontrol edin
🛡️ GÜVENLIK ÖNERİLERİ
1.
Düzenli Yedek Alın - Haftada bir yedek alın
2.
Güncellemeleri Takip Edin - vBSEO güncellemelerini kontrol edin
3.
File Permissions - Dosya izinlerini 644 olarak tutun
4.
Admin Paneli Şifresi - Güçlü ve karmaşık şifre kullanın
5.
Error Logging - Error log'u düzenli kontrol edin
📋 YAPILAN DEĞİŞİKLİKLER
Yapılan Güvenlik Yamaları:
FİKS 1-2: init() - Undefined index hatası (isset() kontrolü)
FİKS 3: get_template() - Path Traversal önleme (Input validation)
FİKS 4: get_template() - Undefined index hatası (isset() kontrolü)
FİKS 5: get_template() - RCE açığı (preg_replace_callback)
FİKS 6: lang() - Undefined index hatası (isset() kontrolü)
FİKS 7: check_preset_match() - Undefined index hatası (isset() kontrolü)
FİKS 8-9: get_product() - SQL Injection + Undefined index (vbseo_db_escape + isset())
FİKS 10: save_settings() - Dosya yazma hataları (Atomic operation)
FİKS 11: detect_presets() - Undefined index hatası (isset() kontrolü)
FİKS 12: proc_deutf() - RCE açığı (preg_replace_callback)
FİKS 13: proc_array() - eval() kontrol (isset() kontrolü)
Tüm orijinal fonksiyonlar korunmuş, sadece güvenlik açıkları kapatılmıştır!
📥 DOSYA İNDİRME
Bilgilendirme: Güncel Dosya İndir
Zip Şifresi:
Kod: Kodu kopyalamak için üzerine çift tıklayın!
www.netguc.com
📞 DESTEK
Sorunlar yaşarsanız:
- Admin paneline giriş yapamıyorsanız: includes/functions_vbseocp_abstract.php.backup dosyasını geri yükleyin
- Hata alıyorsanız: Error log'u kontrol edin (logs/ klasörü)
Tüm açıklar kapatılmıştır. Sisteminiz artık güvenlidir!
Dosya Durumu: ✅ GÜVENLI VE STABIL
Orijinal Yapı: ✅ KORUNMUŞ
Performans: ✅ AYNI VEYA DAHA İYİ
PHP Uyumluluğu: ✅ 5.6 - 8.x
MySQL Uyumluluğu: ✅ 5.6+
Güvenlik Yaması Başarıyla Uygulandı!