CVE-2022-21663 WordPress Nesne Yerleştirme Güvenlik Açığı

a3b2jeo.png

logo.png



WordPress 5.8.3 Nesne Yerleştirme Güvenlik Açığı Nedir ?

Bu yazının yazıldığı sırada, WordPress İnternet'teki web sitelerinin %43'üne güç sağlıyor. Basitliği ve sağlamlığı, milyonlarca kullanıcının bloglarını, e-Ticaret sitelerini, forumlarını veya statik web sitelerini barındırmasına olanak tanır. Kullanıcılarını korumak için geçmişte kod tabanına çeşitli güvenlik güçlendirme mekanizmaları getirilmişti.


WordPress çekirdeğinde yakın zamanda 5.8.3 sürümüyle düzeltilen ilginç bir Nesne Enjeksiyonu güvenlik açığını (CVE-2022-21663) keşfettik . Nesne Enjeksiyonu, saldırganların uygulamaya rastgele türdeki PHP nesnelerini enjekte etmelerine olanak tanıyan ve daha sonra çalışma zamanında uygulamanın mantığını kurcalayabilen bir kod güvenlik açığıdır.

Bu özel güvenlik açığından yararlanmak zor olsa da, bu tür ciddi güvenlik açıklarının hala karmaşık ve güçlendirilmiş kod tabanlarında bulunduğunu gösteriyor. Bu blog yazısında savunmasız kod satırlarını inceliyoruz ve WordPress çekirdeğindeki ilginç bir saldırı yüzeyini ortaya çıkarıyoruz.



Açığı İnceleyelim

Bir WordPress sitesi yüzlerce farklı seçenek tarafından kontrol edilir . Bu seçenekler bir WordPress sitesini yapılandırmak için kullanılır. Temel kodda seçenekler, fonksiyon yardımıyla veritabanından alınır get_option($key) ve fonksiyon yardımıyla güncellenir update_option($key, $value) . Zamanla, bir WordPress sitesinde saklanan seçeneklerin listesi genellikle WordPress eklenti geliştiricileri ve hatta çekirdek geliştiriciler, bir kullanıcı veya hatta yönetici tarafından değiştirilmesi amaçlanmayan dahili verileri seçenek çiftleri olarak depolama eğiliminde oldukça büyür.


Ancak bir WordPress sitesinin yöneticisi olarak, veritabanında depolanan hemen hemen tüm seçenek anahtar/değer çiftlerini listelemek ve değiştirmek mümkündür. Aşağıdaki ekran görüntüsü, bir test örneğinde
/wp-admin/options.php adresindeki sayfayı ziyaret ederek elde edilen seçeneklerin listesini gösterir

1111.png


Yukarıdaki ekran görüntüsündeki bazı seçenek adları, bunlarla ilişkili verilerin dahili süreçlere yönelik olduğunu ve bir yönetici tarafından değiştirilmemesi gerektiğini göstermektedir. Örneğin, seçeneğin değeri active_plugins : ekran görüntüsünde, değeriyle birlikte grileştirilmiş bir alan olarak görüntülenir SERIALIZED_DATA.

WordPress geliştirici referansında belgelendiği gibi
update_option($key, $value) işlev, serileştirilebildiği sürece nesneleri, dizileri, tam sayıları, dizeleri ve diğer türleri değer olarak alabilir. Böyle bir durumda, PHP serileştirilmiş bir dize veritabanında saklanır.

WordPress çekirdeği, bir dizenin daha önce seri hale getirilip getirilmediğini kontrol ederek ve öyleyse onu çift seri hale getirerek hiçbir seri durumdan çıkarma saldırısının gerçekleştirilememesini sağlar. Bu, fonksiyon tarafından yapılır
maybe_serialize($data) :

wordpress/wp-includes/functions.php

Kod:
597  function maybe_serialize( $data ) {
 598         if ( is_array( $data ) || is_object( $data ) ) {
 599                 return serialize( $data );
 600         }
 601
 602         /*
 603          * Double serialization is required for backward compatibility.
 604          * See https://core.trac.wordpress.org/ticket/12930
 605          * Also the world will end. See WP 3.6.1.
 606          */
 607         if ( is_serialized( $data, false ) ) {
 608                 return serialize( $data );
 609         }
 610
 611         return $data;

Fonksiyonun simetrik ikizi maybe_serialize($data) fonksiyondur maybe_unserialize($data) :

wordpress/wp-includes/functions.php

Kod:
wordpress/wp-includes/functions.php
 622 function maybe_unserialize( $data ) {
 623         if ( is_serialized( $data ) ) {
 624                 return @unserialize( trim( $data ) );
 625         }
 626
 627         return $data;
 628 }

is_serialized($data) Her iki işlevin de bir dizenin PHP hardened dizeye benzeyip benzemediğini tespit etmek için nasıl kullanıldığına dikkat edin . Bir sonraki bölümde, bu işlevin WordPress çekirdeğinde yanlış kullanılması nedeniyle ortaya çıkan Nesne Enjeksiyonu güvenlik açığı hakkında ayrıntılı bilgi verilmektedir.

WordPress gelen bir isteği her ele aldığında, doğrulama adımlarının bir listesini yürütür. Bu adımlardan biri, WordPress kurulumuyla ilişkili veritabanı sürümünün mevcut kod dosyalarının sürümüyle eşleştiğinden emin olmaktır.

Yayımlanan her yeni WordPress sürümü için en son veritabanı sürümü genel bir değişkende güncellenir:

wordpress/wp-includes/version.php

Kod:
18 /**
 19  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
 20  *
 21  * @global int $wp_db_version
 22  */
 23 $wp_db_version = 49752;

Yukarıdaki kod gösterilen sürüm, veritabanının tamamen yükseltildiğinde olması gereken sürümdür . Veritabanının istek sırasındaki sürümü bir WordPress seçeneği olarak saklanır. Aşağıdaki kod parçası bu seçeneğin veritabanından nasıl getirildiğini gösterir. Olması gereken sürüme eşit olduğunda herhangi bir işlem yapılmaz ve istek işleme alınır. Sürüm senkronize değilse, aşağıda gösterildiği gibi bir dizi yükseltme komut dosyası çalıştırılır:
Kod:
wordpress/wp-admin/includes/upgrade.php
 636 function wp_upgrade() {
 637   global $wp_current_db_version, $wp_db_version, $wpdb;
 638
 639   $wp_current_db_version = __get_option( 'db_version' );
 640
 641   // We are up to date. Nothing to do.
 642   if ( $wp_db_version == $wp_current_db_version ) {
 643       return;
 644   }
 645
 646   if ( ! is_blog_installed() ) {
 647       return;
 648   }
 649
      // …
 654   upgrade_all();
 754       // …
 755   if ( $wp_current_db_version < 8989 ) {
 756       upgrade_270();
 757   }
 758
 759   if ( $wp_current_db_version < 10360 ) {
 760       upgrade_280();
 761   }
 762   // …

Bu davranış ilginçtir, çünkü kötü niyetli bir yönetici $wp_current_db_version kontrol edilebilir bir seçenek olduğundan keyfi bir değere ayarlayabilir. Böylece bir saldırgan, kullanıcılar ve gönderilerle ilişkili seçenek değerleri ve meta veriler gibi kontrol edilebilir veriler üzerinde çalışanlar da dahil olmak üzere herhangi bir veritabanı yükseltme komut dosyasını çalıştırabilir. Bu yetenek, saldırganın WordPress çekirdeğindeki ilginç bir saldırı yüzeyine erişmesini sağlar.

Yürütülen yükseltme komut dosyası
upgrade_280() özellikle ilgi çekicidir:

wordpress/wp-admin/includes/upgrade.php

Kod:
wordpress/wp-admin/includes/upgrade.php
1605 function upgrade_280() {
1606     global $wp_current_db_version, $wpdb;
1607
1608     if($wp_current_db_version < 10360 ) {
1609         populate_roles_280();
1610     }
1611     if(is_multisite() ) {
1612         $start = 0;
1613         while($rows = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options ORDER BY option_id LIMIT $start, 20")){
1614             foreach ( $rows as $row ) {
1615                 $value = $row->option_value;
1616                 if ( ! @unserialize( $value ) ) {
1617                     $value = stripslashes( $value );
1618                 }

Bu yükseltme betiği, 1613 satırındaki veritabanından seçenekleri getirir ve bunları 1616 satırındaki seri durumdan çıkarmaya çalışır. Dikkat edilmesi gereken önemli ayrıntı, PHP'nin yerleşik unserialize() işlevinin olağan değil, doğrudan kullanılmasıdır maybe_unserialize(). Aşağıdaki paragraflarda bu davranışın neden ilginç olduğu ve nasıl Object Injection güvenlik açığına yol açtığı açıklanacaktır.

Daha önce tartışıldığı gibi, kötü niyetli bir yönetici seçeneklerin değerlerini neredeyse keyfi olarak kontrol edebilir ve bu nedenle serileştirilmiş bir PHP dizesini veritabanına enjekte etmeye çalışabilir. Kısıtlamalardan biri, serileştirilmiş bir PHP dizesi tespit edildiğinde yeniden serileştirilmesi ve dolayısıyla zararsız hale gelmesidir.


Örnek olarak, bir saldırgan bir seçeneğin değerini aşağıdaki hardened dizeye ayarlamaya çalışırsa:

Kod:
O:20:"SuperDangerousGadget":1:{s:18:"dangerous_property";s:8:"bash ...";}

şu şekilde çift hardened yapılır:

Bu çift serileştirmenin sonucu, serileştirilmediğinde yükün zararsız hale gelmesidir, çünkü bu bir dizeyle sonuçlanacaktır.


unserialize() Sonuç olarak, WordPress kodu ile PHP çekirdeğindeki kod arasındaki mantıkta bir fark bulma umuduyla, WordPress çekirdeğinde bir dizenin serileştirilip serileştirilmediğini gerçekten algılayan koda baktık.

unserialize() Bir hatırlatma olarak: PHP'nin işlevi tarafından desteklenen türlerden bazıları şunlardır :
TYPEEXAMPLE OF SERIALIZED STRING
Integeri:1337;
Floatd:1337;
Strings:15:"hack the planet";
ObjectO:8:"stdClass":0:{}
Object with custom deserialization function (available in PHP < 7.4)C:11:"ArrayObject":21:{x:i:0;a:0:{};m:a:0:{}}


Aşağıda is_serialized($data) WordPress çekirdeğindeki fonksiyondan bir kod alıntısı yer almaktadır. Bu işlev, sağlanan girdinin ilk karakterini, bu dizenin hardened bir PHP dizesi olabileceğini gösteren bir karakter listesiyle karşılaştırır ve ardından daha fazla karşılaştırma yapar. Geçiş durumlarında özel nesnelerin karakterinin nasıl C dikkate alınmadığına dikkat edin:

wordpress/wp-includes/functions.php

Kod:
677     $token = $data[0];
 678     switch ( $token ) {
 679         case 's':
 680             if ( $strict ) {
 681                 if ( '"' !== substr( $data, -2, 1 ) ) {
 682                     return false;
 683                 }
 684             } elseif ( false === strpos( $data, '"' ) ) {
 685                 return false;
 686             }
 687             // Or else fall through.
 688         case 'a':
 689         case 'O':
 690             return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
 691         case 'b':
 692         case 'i':
 693         case 'd':
 694             $end = $strict ? '$' : '';
 695             return (bool) preg_match( "/^{$token}:[0-9.E+-]+;$end/", $data );
 696     }
 697     return false;

Genellikle bu bir sorun olmaz. Bu işlev, serileştirilmiş dizenin a ile başladığı özel nesneleri kaçırdığından C, bir saldırgan bu tür serileştirilmiş bir PHP dizesini veritabanına enjekte edebilir. Bununla birlikte, işlev dizeyi yalnızca ile hardened bir dize olarak tanındığında maybe_unserialize() PHP'ye ilettiği için , hiçbir zaman hardened olmıcaktır.unserialize()maybe_serialize()

Daha önce açıklanan yükseltme komut dosyasındaki bu simetri
maybe_unserialize() bozuldu . maybe_serialize() Dizeyi doğrudan PHP'nin unserialize() işlevine iletir.


Sonuç olarak, bir saldırgan bu güvenlik açığından yararlanmak için aşağıdaki adımları gerçekleştirebilir:

Kötü amaçlı pop zinciri gadget'larını özellikler olarak taşıyan özel bir nesnenin PHP serileştirilmiş dizesini, bir seçenek değeri olarak veritabanına enjekte edin.

maybe_serialize() yükü serileştirilmiş bir dize olarak tanımaz ve onu iki kez serileştirmez.
Güvenlik açığı bulunan yükseltme komut dosyasını tetiklemek için veritabanı sürümü seçeneğini değiştirin

Yükseltme betiği, PHP'nin seri hale getirilmiş dizesini doğrudan öğesine iletir unserialize(); bu dizeyi tanır ve seri durumdan çıkararak pop zincirini tetikler.

Yama Güncellemesi

WordPress, bu kod güvenlik açığını WordPress 5.8.3 sürümünde bulunan bir yama işlemiyle düzeltti . Güvenlik açığı, ve arasındaki asimetriyi düzeltmek için güvenlik açığı işlevi kullanılarak giderildi .maybe_unserialize($data)upgrade_280()maybe_serialize($data)unserialize($data)


Konumu Okuduğunuz İçin Teşekkür Ederim.


Yararlandığım Kaynaklar:
1.SonarLint
2.https://developer.wordpress.org/reference/functions/update_option/
3.https://developer.wordpress.org/plugins/settings/options-api/

a3b2jeo.png
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.