1 puan yazan GN⁺ 2024-10-18 | 1 yorum | WhatsApp'ta paylaş
  • Chromium’un WebUI yetki sınırı, kurumsal politika test özelliği ve DevTools uzantı API’sindeki kusur bir araya gelince, kötü amaçlı bir Chrome uzantısı çok az kullanıcı etkileşimiyle kabuk komutu çalıştırma noktasına kadar ulaşabildi
  • Saldırı zinciri, chrome://policy üzerinde belgelenmemiş politika test API’sini çağırarak kullanıcı politikalarını değiştirmeye ve Browser Switcher’ın alternatif tarayıcı yolu ile argümanlarını kabuk komutu olarak kötüye kullanmaya dayanıyordu
  • chrome.devtools.inspectedWindow.reload() injectedScript çalıştırılmasına izin veriyordu; ayrıca WebUI’ye geçiş anındaki erişim engellemesindeki gecikme veya çökmeden sonra kalan Page.reload isteği nedeniyle ayrıcalıklı WebUI içinde kod çalıştırılabiliyordu
  • Google, açıkları P1/S1 olarak sınıflandırdı ve Page.reload için loaderId doğrulaması, inspectedWindow.reload() için URL kontrolü ve WebUI işleyicisinde politika testinin etkin olup olmadığını denetleyen kontroller ekledi
  • İlgili açıklar CVE-2024-5836 ve CVE-2024-6778 olarak atandı; ikisi de CVSS 8.8 High aldı ve nihai ödül $20,000 oldu

Chromium WebUI ve sandbox sınırı

  • Chromium, güvenilmeyen kodu sandbox içinde çalıştırır; Chrome uzantılarının JavaScript’i de yalnızca verilen izinler ve erişebildiği API’ler içinde çalışmalıdır
  • Yalnızca uzantı izinleriyle bile oturum açma bilgileri veya tarayıcı geçmişi çalınabilir, ancak ilke olarak etki alanı tarayıcının içinde kalmalıdır
  • Chromium’un GUI’sinin bir bölümü chrome://settings, chrome://history gibi WebUI olarak uygulanır
    • WebUI, HTML, CSS ve JavaScript ile yazılır; ancak tarayıcı içi bilgileri göstermesi ve değiştirmesi gerektiğinden normal web sayfalarından daha yüksek ayrıcalıklara sahiptir
    • WebUI ön yüzünün JavaScript’i, özel API’ler üzerinden tarayıcının yerel C++ koduyla iletişim kurabilir
  • WebUI içinde kod çalıştırılabiliyorsa bu, Chromium sandbox’ını aşmaya kadar gidebilir; bu yüzden saldırganların chrome:// sayfalarında güvenilmeyen JavaScript çalıştıramaması önemlidir
  • Örneğin chrome://downloads içinde bir .exe indirme öğesine tıklanırsa çalıştırılabilir dosya açılabilir; bu nedenle Chromium, dosya açma eyleminin gerçekten kullanıcı girdisinden gelip gelmediğini kontrol eder

Kurumsal politika test özelliğinin aşılması

  • Açık araştırması, Chromium’un enterprise policy system bileşeninde başladı
    • Bu sistem, şirket veya okul sahipli cihazlarda yöneticilerin belirli ayarları zorunlu olarak uygulaması için kullanılan bir özelliktir
    • Politikalar genellikle Google hesabına bağlanır ve Google yönetim sunucularından indirilir
  • Politikalar device policies ve user policies olarak ayrılır
    • device policies, Chrome OS cihazının tamamındaki ayarları yönetir
    • user policies, belirli bir kullanıcıya veya tarayıcı örneğine uygulanır ve tüm platformlarda kullanılabilir
    • Linux’ta /etc/opt/chrome/policies içine JSON dosyaları yerleştirerek Google Chrome örneğine user policies uygulanabilir, ancak bu dizine yazmak için root yetkisi gerekir
  • Cihaza o anda uygulanan politikalar chrome://policy WebUI’sinden görülebilir
    • Bu sayfa uygulanan politika listesini, politika hizmeti günlüklerini ve JSON dışa aktarma işlevini sunar
    • Normalde bu sayfada politikaları düzenlemenin bir yolu yoktur
  • Chrome v117 Chrome Enterprise sürüm notlarında, chrome://policy/test sayfasının Beta, Dev ve Canary kanallarında politika testine izin verdiğine dair bir madde yer aldı
    • Bu özellik, ilgili sürüm notları dışında Chromium belgelerinde anılmıyordu
    • Normal şekilde etkinleştirmek için belgelenmemiş PolicyTestPageEnabled politikası gerekiyordu
    • Bu politika yoksa chrome://policy/test, chrome://policy sayfasına yönlendiriliyordu

setLocalTestPolicies doğrulama hatası

  • chrome://policy/test içindeki JavaScript kodu, test politikalarını ayarlamak için sendWithPromise('setLocalTestPolicies', ...) kullanıyordu
    • sendWithPromise(), WebUI’nin özel API’si chrome.send() için bir sarmalayıcıdır
    • Bu çağrı C++ işleyici fonksiyonuna istek gönderir ve işleyici tarayıcı içinde dahili işlemler gerçekleştirebilir
  • chrome://policy konsolundan doğrudan setLocalTestPolicies çağrıldığında, ilk denemede tarayıcı çöktü ve günlükte politika dizisinin gerekli olduğuna dair bir mesaj kaldı
  • Politika dizisi biçimi düzeltilip AllowDinosaurEasterEgg gibi bir user policy gönderildiğinde, özellik açıkça etkinleştirilmemiş olmasına rağmen keyfi politikalar ayarlanabildi
  • C++ tarafındaki HandleSetLocalTestPolicies işleyicisi yalnızca local_test_provider var mı diye bakıyordu; politika test özelliğine gerçekten izin verilip verilmediğini kontrol etmiyordu
  • LocalTestPolicyProvider::CreateIfAllowed(), IsPolicyTestingEnabled(nullptr, channel) çağrısı yapıyordu
    • İlk argüman olan pref_service null olduğu için PolicyTestPageEnabled kontrolü atlanıyordu
    • Geriye yalnızca release channel’ın CANARY veya DEFAULT olup olmadığı kontrolü kalıyordu
  • markasız Chromium derlemelerinde GOOGLE_CHROME_BRANDING kodu derlenmediği için kanal UNKNOWN olarak kalıyordu
    • enum içinde UNKNOWN = 0, DEFAULT = UNKNOWN olduğundan Chromium ve türev derlemelerde kanal kontrolü geçiliyordu
    • markalı Google Chrome stable derlemelerinde release channel doğru ayarlandığından bu hata stable Google Chrome’da çalışmıyordu

Browser Switcher ile kabuk komutu çalıştırma

  • Keyfi user policy ayarlanabilince, Chrome kurumsal politikalarındaki Legacy Browser Support modülü sandbox kaçış yolu haline geldi
  • Legacy Browser Support, Browser Switcher olarak da bilinir; kullanıcı Chromium’da belirli bir URL’yi ziyaret ettiğinde alternatif bir tarayıcı başlatmak için tasarlanmıştır
    • Özellik, Internet Explorer kullanıcı desteği için oluşturulmuştur
    • Davranışı politikalarla kontrol edilir
  • AlternativeBrowserPath ve AlternativeBrowserParameters politikaları birleştirildiğinde, Chromium “alternatif tarayıcı” olarak keyfi kabuk komutları çalıştırabiliyordu
    • Bu Browser Switcher politikaları yalnızca Linux, macOS ve Windows’ta vardır
  • Örnek akış şöyledir
    • BrowserSwitcherEnabled değeri true yapılır
    • BrowserSwitcherUrlList içine example.com eklenir
    • AlternativeBrowserPath Linux’ta /bin/bash olarak ayarlanır
    • AlternativeBrowserParameters ise ["-c", "xcalc # ${url}"] gibi ayarlanır
  • Tarayıcı example.com adresine gittiğinde Browser Switcher devreye girer ve /bin/bash -c 'xcalc # https://example.com' biçiminde bir komut çalıştırılır
    • ${url} yerine geçen değer, kabuk yorumu olması için # sonrasına yerleştirilir
  • chrome://policy içinde politikalar ayarlandıktan sonra window.open("https://example.com";) çağrısı yapmak, yalnızca JavaScript ile keyfi kabuk komutu çalıştırılmasına kadar gidiyordu

DevTools uzantı API’sindeki atlatma yolu

  • Yalnızca önceki adımlar kullanılırsa kurbanın chrome://policy üzerinde tarayıcı konsoluna kötü amaçlı kod yapıştırması gerektiğinden pratik değildi
  • Otomatik yürütme yolu, kötü amaçlı bir Chrome uzantısı üzerinden bulundu
    • Uzantılar sayfaya JavaScript enjekte edebilir, ancak ayrıcalıklı WebUI sayfalarında JavaScript çalıştıramamaları gerekir
  • Uzantıların sayfada JavaScript çalıştırmak için kullandığı başlıca dört API vardı
    • chrome.scripting
    • Manifest v2’deki chrome.tabs
    • chrome.debugger
    • chrome.devtools.inspectedWindow
  • İnceleme için, görece daha az sertleştirilmiş olduğu düşünülen chrome.devtools.inspectedWindow seçildi
    • chrome.devtools API’sini kullanan uzantıların manifest içinde devtools_page alanına sahip olması gerekir
    • Kullanıcı DevTools’u açtığında bu sayfa bir iframe olarak yüklenir ve içeride chrome.devtools API’si kullanılabilir
  • David Erceg’in önceki hata raporunda, chrome.devtools.inspectedWindow.eval() kullanılarak WebUI içinde kod yürütmeye ulaşılan bir örnek vardı
    • Normalde incelenen sayfa WebUI’ye geçtiğinde DevTools API kullanımının devre dışı bırakılması gerekir
    • Atlatmanın ana fikri, Chrome API’yi devre dışı bırakmadan önce eval isteğini gönderip isteğin WebUI sayfasına ulaşmasını sağlamaktı

inspectedWindow.reload() ve about:blank özelliği

  • chrome.devtools.inspectedWindow.reload() da injectedScript argümanını alırsa incelenen sayfada JavaScript çalıştırabilir
  • WebUI’nin açtığı bir about:blank sayfasında inspectedWindow.reload() çağrıldığında, ayrıcalıklı sayfada JavaScript yürütülebiliyordu
    • about:blank URL olarak özel görünmese de kendisini açan sayfanın izinlerini ve origin’ini devralır
    • chrome://settings tarafından açılan about:blank, chrome://settings origin’ine sahip ayrıcalıklı bir sayfaydı
  • DevTools API’yi devre dışı bırakan kod, incelenen hedefin yalnızca URL’sini kontrol ediyor, origin’i kontrol etmiyordu
    • URL normal görünse bile origin ayrıcalıklı bir origin olabilir
  • Yalnız about:blank yolu, chrome://policy about:blank açılır penceresi oluşturmadığı için exploit zincirinde doğrudan kullanılamıyordu
  • Ancak inspectedWindow.eval() başarısız olurken bile inspectedWindow.reload(), chrome://settings içinde JavaScript çalıştırabiliyordu
    • Bu, eval() içinde origin kontrolüne denk bir denetim varken reload() içinde aynı düzeyde bir kontrol olmadığını gösteriyordu

Yarış durumundan çökme tabanlı yönteme geçerek kararlılık sağlama

  • İlk exploit zinciri, inspectedWindow.reload() çağrısını tekrar tekrar yaparak, incelenen sayfanın WebUI’ye geçmesinden hemen sonra DevTools sayfası API’yi devre dışı bırakmadan önceki kısa pencereyi hedefliyordu
    • Bunun için incelenen sayfa ile DevTools sayfasının farklı süreçlerde çalışması gerekiyordu
    • chrome://policy sayfasına geçiş anı ile DevTools API’sinin devre dışı bırakılması arasına reload() isteği girerse WebUI içinde kod çalışıyordu
  • Bu yöntem işe yaradı ama güvenilirliği düşüktü
    • Ayarlamalar sonrasında yaklaşık %70 başarı sağlanabildi
    • Açık ciddi olsa da kararsızlık severity değerlendirmesini düşürebilirdi
  • Daha sonra, David Erceg’in önceki yaklaşımındaki gibi, sekme çökmesinden sonra kalan debugger istekleri davranışının inspectedWindow.reload() için de kullanılabilir olup olmadığı denendi
  • debugger ifadesi art arda iki kez tetiklendiğinde sekme çöküyor ve kuyruğa alınmış Page.reload isteği WebUI’ye geçildikten sonra çalışabiliyordu
    • Bu yöntem yarış durumunu gereksiz kılarak %100 güvenilir hale geldi
  • Google, önceki hata yamasında çökme sonrasında bekleyen debugger isteklerini temizleyecek değişikliği yapmıştı, ancak Page.reload isteklerini istisna olarak bırakmıştı
    • inspectedWindow.reload() dahili olarak Page.reload isteği gönderdiği için bu istisnadan etkileniyordu
    • O dönemdeki yama, Page.reload komutunun betik çalıştırabildiği gerçeğini engelleyememişti
  • Sekme çökmesi, debugger yöntemi dışında bellek yetersizliği oluşturularak da tetiklenebiliyordu; ancak nihai PoC’de daha hızlı olan debugger çökmesi kullanıldı

Nihai exploit zinciri ve kullanıcı etkileşimi

  • Nihai PoC şu sırayla çalışıyordu
    • chrome.devtools.inspectedWindow.reload() açığı kullanılarak chrome://policy içinde JavaScript payload çalıştırılır
    • payload, kullanıcı politikalarını ayarlamak için sendWithPromise("setLocalTestPolicies", policy) çağrısı yapar
    • BrowserSwitcherEnabled, BrowserSwitcherUrlList, AlternativeBrowserPath, AlternativeBrowserParameters ayarlanır
    • window.open() veya sayfa yönlendirmesiyle Browser Switcher tetiklenir ve kabuk komutu çalıştırılır
  • PoC, işletim sistemine göre hesap makinesi açma komutlarını kullanıyordu
    • Windows: C:\Windows\System32\cmd.exe ve calc.exe
    • Linux: /bin/bash ve xcalc
    • macOS: /bin/bash ve open -na Calculator
  • Kullanıcı etkileşimi, DevTools’un açılmasını sağlayacak kadarla sınırlıydı
    • Örnek ekrandaki “extension install error” mesajı, kullanıcıyı DevTools açmaya kandırmak için kullanılan bir yöntemdi
    • DevTools açıldığında sandbox kaçışına giden zincir başlıyordu

Google’ın düzeltmeleri ve CVE atamaları

Açıklanma takvimi ve kaynaklar

  • Zaman çizelgesi şöyleydi
    • 16 Nisan: test policies hatası bulundu
    • 29 Nisan: inspectedWindow.reload() yarış durumu hatası bulundu
    • 1 Mayıs: açıklar Google’a bildirildi
    • 4 Mayıs: Google, açıkları P1/S1 olarak sınıflandırdı
    • 5 Mayıs: incelenen sayfanın çökmesiyle ilgili hata bulunup rapor güncellendi
    • 6 Mayıs: Google, zincirin her parçası için ayrı hata raporları istedi
    • 8 Temmuz: hata raporları fixed olarak işaretlendi
    • 13 Temmuz: ödül kararı için Chrome VRP paneline iletildi
    • 17 Temmuz: VRP paneli $20,000 ödül kararı verdi
    • 15 Ekim: tüm hata raporları kamuya açıldı
  • İlgili özgün hata raporu crbug.com/338248595 adresinde görülebilir
  • Açığın her parçasına ait PoC’ler GitHub deposunda yayımlandı
  • inspectedWindow.reload hatası Chrome v45’e kadar geri giderek çalışıyordu
  • Belgelenmemiş, tamamlanmamış ve güvensiz özellikler tüm kullanıcılara dağıtıldığında, basit hatalar birleşerek yüksek ciddiyette açıklara dönüşebilir

1 yorum

 
GN⁺ 2024-10-18
Hacker News yorumları
  • Sayfa URL’sinin ${url} ile değiştirildiği ve komutu bozmaması için # işaretinden sonrasına koyulursa yorum satırı olacağı söylenmiş; peki bu politikada URL’nin AlternativeBrowserParameters içinde bir yerlere aktarılması gerektiğini doğrulayan bir mantık var mı?

  • Programlama, web geliştirme ve siber güvenlikle ilgilenen bir lise öğrencisi olması gerçekten etkileyici

    • İnanılmaz teknik yetenek, azim, dokümantasyon ve iletişim becerileri; hepsi çok güçlü
      Sorumlu açıklama sürecine uymasıyla gösterdiği meslek etiği de harika; ileride çok büyük işler yapacak biri gibi görünüyor
  • Harika bir yazı ve çalışmaydı; keşifler ilerledikçe heyecanın nasıl biriktiğini birlikte takip ediyormuş gibi hissettirdi
    Ödülü de fazlasıyla hak ediyor

  • Açıkların birbirine bağlanma süreci de temiz, yazı da harika. Savunmasız kodun nasıl çalıştığını parçalara ayırıp göstermesi de çok iyiydi
    “Yeniden denemek için F12’ye basın” gibi basit numaralar her gördüğümde hayran bırakıyor; gerçekten çok muzipçe

    • Missouri’de yaşıyorum; bir keresinde F12’ye basmıştım, vali beni tutuklatmaya çalışmıştı
  • Eskiden aynı API ile Chrome OS’in crosh kabuğunda hata ayıklayıp işletim sistemi korumalarını aşarak geliştirici cihazında root erişimi elde ettiğim bir olayı hatırlattı. CVE-2014-3172 idi
    Ancak bu yazının yazarı çok daha zor engelleri aşmak zorunda kalmış; gerçekten harika bir çalışma

  • Gece çok geç olduğu için WebUI doğrulamasında neyin bozulduğunu derinlemesine incelemek zor, ama sonuna kadar gidip bunu çözmüş olması hoşuma gitti
    Dağıttığımız şeylerin araç zincirinden şüphe etmek ve ona güvenmemek oldukça standart bir tutum; buna karşılık Google veya Microsoft gibi büyük şirketlerin sihirli derecede kullanışlı geliştirme araçlarına fazlasıyla güveniyoruz. Sonuçta Chromium’un ya da VSCode’un içinde ne saklı olduğundan endişelenmektense kendi kodumu yazıp test etmek istiyoruz

  • Okuduklarım arasında açık ara en iyi yazılardan biri
    Gerçekten çok zekice bir iz sürme çalışmasıydı

  • Tarayıcı kodunu kurcalayıp buraya kadar bulma çabası müthiş; yazı da çok ilginç ve ayrıntılı

  • Lise öğrencisiymiş, vay be gerçekten harika

  • Chromium projesi, chrome://net-internals’ı fazla karmaşık olduğu gerekçesiyle kaldırıp yerine yarım yamalak JSON düzenleme desteği eklenmiş chrome://policy sayfasını koydu