İçeriğe atla
Noroxi
Araştırma9 dk

Premium Addons for Elementor: Bozuk Erişim Denetimi (CWE-862)

Premium Addons for Elementor 4.11.110'daki iki yetki denetimi eksikliği, Katkıda Bulunan'a yazı yayımlatıyor, anonim ziyaretçiye özel şablon okutuyor.

Noroxi EkibiSızma testi ve güvenlik danışmanlığı

Özet. WordPress eklenti açıklarının çoğu bellek bozulması değil; çağırana "bunu yapmaya iznin var mı?" diye sormayı unutan işleyicilerdir. Premium Addons for Elementor 4.11.110 bunlardan ikisini taşıyor. Biri Katkıda Bulunan'a (Contributor) yayımlanmış yazı oluşturtuyor; diğeri, platformun özel tuttuğu Elementor kitaplık şablonlarını anonim bir ziyaretçiye okutuyor. Aşağıda kök neden kodu, her denetime nasıl ulaşıldığının kavramsal anlatımı ve savunma adımları var. Eşgüdümlü açıklama gereği, çalışır kavram kanıtı yama çıkana kadar bu yazıda yer almıyor.

Anahtar sözcükler: bozuk erişim denetimi, yetki denetimi eksikliği, CWE-862, yetenek denetimi, nonce ile yetenek farkı, Elementor, WordPress AJAX güvenliği.

1. Giriş

Premium Addons for Elementor, Elementor sayfa oluşturucusu için yaygın bir widget paketi; 600.000'den fazla sitede etkin. Bu yaygınlık onu iyi bir örnek yapıyor. Buradaki hatalar egzotik değil; WordPress eklentilerinde en sık görülen açık sınıfı olan yetki denetimi eksikliği (CWE-862). Öğrettikleri ilke neredeyse her eklenti için geçerli: nonce niyeti kanıtlar, izni değil. Nonce'u doğrulayıp hiçbir zaman current_user_can() çağırmayan bir işleyici sık yapılan, etkisi yüksek bir hatadır; Premium Addons bunu iki kez yapıyor.

İki sorunu da eklenti kaynak kodunda doğruladık ve yalıtılmış bir yerel (localhost) laboratuvarda yeniden ürettik; ortam Elementor 4.3.3 ve Premium Addons 4.11.110'du. Önem derecesi dürüstçe orta. Etki sınırlı, ama her ikisi de anlaşılmaya ve savunulmaya değer net birer yetki sınırı ihlali.

2. Etkilenen bileşen

EklentiPremium Addons for Elementor — slug premium-addons-for-elementor
Test edilen sürüm4.11.110 (test sırasında güncel/en son)
Etkin kurulum600.000+
DurumTaze; kodda doğrulandı ve yerel laboratuvarda yeniden üretildi

A) handle_live_editor — Yetki denetimi eksikliği → Katkıda Bulunan YAYIMLANMIŞ yazı oluşturur

TürYetki denetimi eksikliği / Bozuk Erişim Denetimi
CWECWE-862 Missing Authorization
YetkiKatkıda Bulunan (edit_posts olan herhangi bir kullanıcı; normalde yayımlayamaz)
CVSS 3.1~5.4 (Orta) AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L

B) get_elementor_template_content — Kimliği doğrulanmamış Elementor şablon ifşası

TürBozuk Erişim Denetimi / Bilgi İfşası
CWECWE-862 / CWE-200
YetkiKimliği doğrulanmamış
CVSS 3.1~5.3 (Orta) AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

3. Teknik analiz

3.1 Bulgu A — yetenek denetiminin işini gören bir nonce denetimi

includes/extras/live-editor.php (v4.11.110) içinde iki AJAX eylemi, oturum açmış her kullanıcı için kaydediliyor:

php
add_action( 'wp_ajax_update_template_title', array( $this, 'update_template_title' ) );   // line 40add_action( 'wp_ajax_handle_live_editor',   array( $this, 'handle_live_editor' ) );       // line 41

Kardeş işleyici update_template_title() yetkilendirmeyi doğru yapıyor; önce nonce'u, sonra yeteneği denetliyor:

php
public function update_template_title() {    check_ajax_referer( 'pa-live-editor', 'security' );    ...    if ( ! current_user_can( 'manage_options' ) ) {          // <-- capability check present        wp_send_json_error( 'Insufficient user permission' );    }    wp_update_post( ... );}

handle_live_editor() ise yetenek denetimini düşürüyor ve yalnızca nonce'u doğruluyor:

php
public function handle_live_editor() {    check_ajax_referer( 'pa-live-editor', 'security' );       // nonce ONLY — no current_user_can()    if ( ! isset( $_POST['key'] ) ) { wp_send_json_error(); }    $key       = sanitize_text_field( wp_unslash( $_POST['key'] ) );    $temp_type = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : false;    wp_send_json_success( self::get_or_create_dynamic_template( $key, $temp_type ) );   // -> wp_insert_post(publish)}

Akışın vardığı nokta yayımlanmış bir yazı oluşturuyor:

php
$post_id = wp_insert_post( array(    'post_content' => '',    'post_type'    => 'elementor_library',    'post_title'   => $post_title,              // 'PA Template | #' . substr(md5($key),0,4)    'post_name'    => $post_name,               // 'pa-dynamic-temp-' . $key   (attacker-controlled slug)    'post_status'  => 'publish',                // <-- PUBLISHED    'meta_input'   => self::get_dynamic_template_meta( $type ),) );

pa-live-editor nonce'u bir izin değil, yalnızca bir CSRF (siteler arası istek sahteciliği) korumasıdır. Oturum açmış kullanıcının bu isteği bilerek başlattığını kanıtlar, o kadar. WordPress yetkilendirmeyi ayrı bir katmanda, yeteneklerde (capabilities) tutar; çünkü "istek gerçek mi" ile "kullanıcının buna izni var mı" ayrı sorulardır. Herhangi bir Katkıda Bulunan, Elementor düzenleyicisini kendi taslağında açabilir ve pa-live-editor nonce'u tam da orada dağıtılır; dolayısıyla nonce denetimini geçmek ona hiçbir şeye mal olmaz. handle_live_editor() bu noktadan sonra bir Katkıda Bulunan'ın asla yapamaması gereken bir yayımlamayı gerçekleştirir. Asıl ipucu tutarsızlık: update_template_title() ve check_temp_validity() manage_options denetimi yaparken, handle_live_editor() ve pa_get_editor_template() yapmıyor.

3.2 Bulgu B — yalnızca yazı durumuyla korunan kimliksiz bir işleyici

includes/helpers/ajax-helper.php (v4.11.110) içinde şablon içeriği işleyicisi kimliği doğrulanmamış kullanıcılar için de kaydediliyor:

php
add_action( 'wp_ajax_get_elementor_template_content',        array( $this, 'get_template_content' ) );  // line 37add_action( 'wp_ajax_nopriv_get_elementor_template_content', array( $this, 'get_template_content' ) );  // line 38  (UNAUTH)

İşleyicide ne nonce var ne de yetenek denetimi. Tek kapısı bir yazı durumu kontrolü ve yayımlanmış yazılar bu kapıdan doğruca geçiyor:

php
public function get_template_content() {    $template = isset($_GET['templateID']) ? sanitize_text_field(wp_unslash($_GET['templateID'])) : '';    $is_ID    = isset($_GET['is_id']) ? filter_var($_GET['is_id'], FILTER_VALIDATE_BOOLEAN) : false;    ...    $post = get_post( $template );    if ( 'publish' !== $post->post_status ) {         // only NON-published posts are gated        if ( ! current_user_can('manage_options') && get_current_user_id() !== (int) $post->post_author )            wp_send_json_error( 'Permission denied' );    }    $template_content = Helper_Functions::render_elementor_template( $template, $is_ID );  // renders & returns HTML    wp_send_json_success( array( 'template_content' => $template_content ) );}

Elementor'un kendi modeli elementor_library öğelerini herkese açık saymaz; ön uçta görüntülemeyi edit_posts olan kullanıcılarla sınırlar ve bunu template_redirect üzerindeki block_template_frontend() ile uygular. Bu AJAX işleyicisi o korumanın yanında durur ve şablonu kendi başına işler. Oysa kitaplık şablonları için publish, tasarımın herkese açık olması gerektiğinin beyanı değil, dahili bir durumdur. Burada o durum, anonim bir ziyaretçiyle herhangi bir kitaplık şablonunun işlenmiş HTML'i arasındaki tek engel hâline geliyor; hiçbir herkese açık sayfaya yerleştirilmemiş şablonlar da buna dâhil.

4. Kusura nasıl ulaşılıyor (kavramsal)

Bulgu A. Ulaşılabilirlik tek bir uyumsuzluğa dayanıyor. İşleyicinin denetlediği şey, yani geçerli bir pa-live-editor nonce'u, tam da o noktaya ulaşmaması gereken kullanıcıların elindedir. Nonce, Elementor düzenleyicisini açabilen herkes için düzenleyiciye gömülür; kendi taslağında düzenleyiciyi açmaksa yalnızca bir Katkıda Bulunan yeteneği olan edit_posts'u ister. İşleyicinin güvendiği kapı, böylece olağan iş akışının doğal bir parçası olarak düşük yetkili bir kullanıcıca karşılanır. Kapıyı geçtikten sonra denetim, koşulsuzca yayımlanmış bir yazı ekleyen bir noktaya varır. Eksik adım, update_template_title()'ın attığı ama handle_live_editor()'ın atlamadığı adım, "bu kullanıcı manage_options tutuyor mu?" sorusudur. Bu soru hiç sorulmadığı için bir Katkıda Bulunan, rol modelinin Editör ve Yönetici'ye ayırdığı bir yayımlamayı yapar. Kusurlu yola varmak için düzenleyiciye olağan, kimlik doğrulamalı erişimden fazlası gerekmiyor; yama beklerken istek düzeyindeki tarifi bilerek vermiyoruz.

Bulgu B. Burada elde edilecek bir nonce bile yok. İşleyici wp_ajax_nopriv_*'a bağlı olduğu için anonim isteklere yanıt verir ve erişimi reddedebilecek tek dalı, hedef yazı publish olduğunda atlanır. Kavramsal boşluk, "yayımlanmış" durumunu "herkese açık" saymaktır. Bu, sıradan yazılar için doğrudur; ama platformun bilinçli olarak bir edit_posts denetiminin arkasında tuttuğu bir nesne sınıfı olan Elementor kitaplık şablonları için doğru değildir. Kimliği doğrulanmamış bir aktör, yalnızca bir şablona başvurarak herhangi bir yayımlanmış kitaplık şablonu için işle-ve-döndür yoluna varır. Yayımlanmamış şablonlar hâlâ korunur; bu da kusurun tam olarak yayımlanmış dalındaki eksik yetenek denetimi olduğunu gösterir. Burada da işlemsel istek ayrıntısı yamayı bekliyor.

5. Etki değerlendirmesi

Bulgu A (CVSS ~5.4, Orta). Katkıda Bulunan düzeyinde bir hesap, saldırganın seçtiği slug'larla keyfi, yayımlanmış elementor_library yazıları oluşturur ve bunu ölçekte yineleyebilir: yetkisiz içerik oluşturma, veritabanı kirliliği ve toplu oluşturmayla küçük bir hizmet reddi. Tavan gerçekten düşük. post_content boş, başlık sabit bir desen izliyor, meta_input bir izin listesi; dolayısıyla burada depolanmış XSS de yok, uzaktan kod çalıştırma da yok. Dürüst özet, orta düzey bir bozuk erişim denetimi sorunu: düşük yetkili bir kullanıcı, Editör ve Yönetici'ye ayrılmış bir yayımlamayı yapıyor. I:L/A:L yetkisiz bütünlük değişimini ve toplu oluşturma rahatsızlığını, PR:L ise gereken Katkıda Bulunan oturumunu yansıtır.

Bulgu B (CVSS ~5.3, Orta). Elementor'un erişim modelinin katkıda-bulunan-ve-üstü kullanıcılarla sınırladığı kitaplık şablonu içeriğinin kimliği doğrulanmamış ifşası: tasarımlar, gömülü metin ve herhangi bir herkese açık sayfaya bağlı olmayan dahili veya hazırlık aşamasındaki şablonlar. Yalnızca gizliliği etkiler (C:L, PR:N); bütünlük veya erişilebilirlik etkisi yok, bu yüzden orta-düşük düzeyde kalır.

6. Giderme

Bulgu A. Yetenek denetimini handle_live_editor()'a kardeş işleyiciyle aynı biçimde ekleyin ve aynısını pa_get_editor_template()'e de uygulayın:

php
if ( ! current_user_can( 'manage_options' ) ) {    wp_send_json_error( 'Insufficient user permission' );}

Bulgu B. İşlemeden önce bir nonce denetimi ekleyin ve Elementor'un kendi görüntüleme politikasını block_template_frontend()'i yansıtacak biçimde zorunlu kılın:

php
check_ajax_referer( 'some-dedicated-nonce', 'security' );if ( ! \Elementor\User::is_current_user_can_edit( $template ) ) {   // i.e. edit_posts on the library item    wp_send_json_error( 'Permission denied' );}

Site işletmecileri, üretici yamalı bir sürüm çıkarır çıkarmaz güncellemeli. O zamana kadar aşağıdaki sıkılaştırmayı uygulayın.

7. Site sahipleri için tespit ve sıkılaştırma

Tam istismar tarifi saklı tutulduğu için aşağıdaki pratik işaretler yalnızca mekanikten çıkarıldı:

  • elementor_library içeriğini denetleyin. pa-dynamic-temp-* biçiminde slug'lar ve PA Template | #XXXX desenine uyan başlıklar taşıyan yayımlanmış kitaplık öğelerine dikkat edin; özellikle Katkıda Bulunan düzeyindeki hesaplarca yazılmışlarsa. Bu tür yazılarda ani bir artış, Bulgu A'nın kullanıldığının en açık işareti.
  • Katkıda Bulunan ve üstünü kimlerin tuttuğunu gözden geçirin. Bulgu A kimliği doğrulanmış bir Katkıda Bulunan ister; o yüzden en az ayrıcalık ilkesini uygulayın: atıl Katkıda Bulunan hesaplarını kaldırın, güçlü kimlik doğrulama isteyin ve edit_posts'u gerekenden geniş dağıtmayın.
  • admin-ajax.php'yi izleyin. handle_live_editor veya get_elementor_template_content eylemlerine yinelenen çağrılar, ikincisi kimliği doğrulanmamış istemcilerden geldiğinde, günlüğe almaya ve hız sınırlamaya değer.
  • Kitaplık şablonlarını hassas kabul edin. Bulgu B yamalanana kadar Elementor kitaplık şablonlarının içinde sır, kimlik bilgisi veya yayımlanmamış metin saklamayın; yayımlanmış kitaplık öğeleri kimlik doğrulaması olmadan okunabilir.
  • Sanal yama. Bir web uygulaması güvenlik duvarı ya da kısa bir must-use eklenti, resmî düzeltme gelene kadar etkilenen eylemlerde bir yetenek denetimini zorunlu kılabilir; bu, işleyicilerin önüne eksik current_user_can()'i eklemenin kavramsal karşılığıdır.
  • Eklentiyi güncel tutun ve üreticinin değişiklik günlüğüne abone olun; böylece yamalı sürüm gecikmeden uygulanır.

8. Daha geniş ders

Durum değiştiren veya veri döndüren her uç nokta, birbirinden bağımsız üç soruyu yanıtlamalı; birini doğru yanıtlamak diğerlerini kapsamaz:

  1. İstek gerçek mi? — nonce / CSRF belirteci.
  2. Kullanıcı iddia ettiği kişi mi? — kimlik doğrulama.
  3. Kullanıcının tam olarak bunu yapmaya izni var mı? — yetenek (current_user_can()).

Her iki bulgu da aynı hatayı yapıyor: 3. soruyu 1. soruya indirgiyor ya da büsbütün atlıyor. Nonce, ürünün olağan iş akışının zaten içindeki herkes için ucuzdur ve yetki hakkında hiçbir şey söylemez. "Yayımlanmış" bir durumdur, bir yetkilendirme kararı değil; bir nesnenin dahili durumunun sessizce onun erişim politikası hâline gelmesine izin vermeyin. Bir kod tabanı bir işleyiciyi yetenekle, aynı güçteki komşusunu yalnızca nonce'la korurken, bu tutarsızlığın kendisi zaten açıktır. Her sink'i açıkça, tam da sink'in yerinde yetkilendirin.

9. Sorumlu açıklama

Bu bulgular eşgüdümlü açıklama kapsamında ele alınıyor. Üreticiye özel olarak, iyi niyetle bildirimde bulunuldu. Tam teknik kavram kanıtı ayrıntısı, yani kesin istek dizisi ve yük değerleri, bir yama çıkana kadar ya da 90 gün (hangisi önce gelirse) boyunca, zamanlaması üreticiyle eşgüdümlü olarak bu herkese açık yazıdan saklı tutuluyor. Tüm testler, herkese açık GPL eklentisine karşı yalıtılmış, yerele (localhost) bağlı bir laboratuvarda yapıldı; hiçbir üçüncü taraf sistemine dokunulmadı ve test eklentileri ile kullanıcıları sonradan kaldırıldı. Noroxi LLC yalnızca yetkili güvenlik araştırması yürütür ve canlı sistemlerin istismarına yardımcı olmaz.

Kaynaklar

Savunma ve eğitim amacıyla yayımlanmıştır. Noroxi LLC yalnızca yetkili güvenlik araştırması yürütür; işlemsel istismar ayrıntısı bir yama çıkana kadar saklı tutulur.

Bu hafta sömürülenler · her pazartesi

KEV'e girenler, yeni PoC'ler, WordPress triyajı ve bu hafta ne yapmalı. Hesap gerekmez.

Adresiniz yalnızca bu e-posta için kullanılır; üçüncü tarafla paylaşılmaz.

Sıradaki

WP Hide & Security Enhancer 2.9.3: "Sonra ayarla" ile 2FA Atlatması