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

Goal: 1000 CNY · Raised: 1000 CNY

100.0%

CVE-2024-34312 PoC — Moodle 安全漏洞

Source
Associated Vulnerability
Title:Moodle 安全漏洞 (CVE-2024-34312)
Description:Moodle是一套免费、开源的电子学习软件平台,也称课程管理系统、学习管理系统或虚拟学习环境。 Moodle v4.2.3 版本及之前版本存在安全漏洞,该漏洞源于 vplide.js 文件中存在跨站脚本漏洞。
Description
☣️ This repository contains the description and a proof of concept for CVE-2024-34312
Readme
# CVE-2024-34312

[![Product](https://img.shields.io/badge/product-Virtual%20Programming%20Lab%20for%20Moodle%20%3C4.2.4-orange?style=for-the-badge&logo=GitHub)](https://github.com/jcrodriguez-dis/moodle-mod_vpl)
[![CWE](https://img.shields.io/badge/CWE-80-%23f0f0f0?style=for-the-badge&logo=OWASP)](https://cwe.mitre.org/data/definitions/80.html)

Description
---
[Virtual Programming Lab for Moodle](https://vpl.dis.ulpgc.es/) **up to v4.2.3** was discovered to contain a **Cross-Site Scripting (XSS)** vulnerability via its **IDE component**.

Additional Details
---
The browser connects directly to a websocket running on the jail server.
Through the websocket, the jail server can send messages directly to the browser. These messages are parsed by the browser and handled by "executionActions".
The "run:browser" action is vulnerable to XSS due to concatenating HTML with untrusted input and injecting it into the page body.
This can be abused by a compromised jail server to gain administrative access on the moodle instance through XSS.

Exploitation
---
An attacker controlling the untrusted jail server, can install a malicious jail server which sends a malicious payload to any user, using the Virtual Programming Lab, triggering XSS.

An example payload would look like this: `run:browser:test\">test</a><script>alert(1)</script><a href=\"test\"`. This would result in `<script>alert(1)</script>` being included in the DOM causing `alert(1)` to be executed.

![image](https://github.com/vincentscode/CVE-2024-34312/assets/26576880/153b7d26-975c-4282-87fd-da961a6f3c55)


The vulnerable code in `vplide.js` interprets this as a command and appends its second argument (arguments are seperated by `:`) to the dom directly:
```js
executionActions = {
    // ...
    'run': function(content, coninfo, ws) {
        var parsed = /^([^:]*):?(.*)/i.exec(content);
        var type = parsed[1];
        if (type == 'terminal' || type == 'webterminal') {
            // ...
        } else if (type == 'vnc') {
            // ...
        } else if (type == "browser") {
            var URL = (coninfo.secure ? "https" : "http") + "://" + coninfo.server + ":" + coninfo.portToUse + "/";
            URL += parsed[2] + "/httpPassthrough";
            if (isTeacher) {
                URL += "?private";
            }
            var message = '<a href="' + URL + '" target="_blank">';
            message += VPLUtil.str('open') + '</a>';
            var options = {
                width: 200,
                icon: 'run',
                title: VPLUtil.str('run'),
            };
            showMessage(message, options);
        } else {
            // ...
        }
    },
    // ...
}
```

Patch
---
```patch
diff --git a/amd/src/vplide.js b/amd/src/vplide.js
index 586b5ff5..d1f88f47 100644
--- a/amd/src/vplide.js
+++ b/amd/src/vplide.js
@@ -2024,8 +2024,8 @@ define(
                 'setResult': self.setResult,
                 'ajaxurl': options.ajaxurl,
                 'run': function(content, coninfo, ws) {
-                    var parsed = /^([^:]*):?(.*)/i.exec(content);
-                    var type = parsed[1];
+                    var parsed = /^([^:]*):?(.*)/.exec(content);
+                    var type = VPLUtil.sanitizeText(parsed[1]);
                     if (type == 'terminal' || type == 'webterminal') {
                         if (lastConsole && lastConsole.isOpen()) {
                             lastConsole.close();
@@ -2055,7 +2055,7 @@ define(
                                 });
                     } else if (type == "browser") {
                         var URL = (coninfo.secure ? "https" : "http") + "://" + coninfo.server + ":" + coninfo.portToUse + "/";
-                        URL += parsed[2] + "/httpPassthrough";
+                        URL += VPLUtil.sanitizeText(parsed[2]) + "/httpPassthrough";
                         if (isTeacher) {
                             URL += "?private";
                         }
diff --git a/amd/src/vplui.js b/amd/src/vplui.js
index 36504a33..648472d6 100644
--- a/amd/src/vplui.js
+++ b/amd/src/vplui.js
@@ -582,8 +582,8 @@ define(
             var messageActions = {
                 'message': function(content) {
                     var parsed = /^([^:]*):?([^]*)/.exec(content);
-                    var state = parsed[1];
-                    var detail = parsed[2];
+                    var state = VPLUtil.sanitizeText(parsed[1]);
+                    var detail = VPLUtil.sanitizeText(parsed[2]);
                     if (state == 'running') {
                         state = running;
                     }
@@ -607,7 +607,7 @@ define(
                     }
                 },
                 'retrieve': function() {
-                    var data = {"processid": VPLUtil.getProcessId()};
+                    var data = {"processid": coninfo.processid};
                     pb.close();
                     delegated = true;
                     VPLUI.requestAction('retrieve', '', data, externalActions.ajaxurl)
@@ -627,7 +627,7 @@ define(
                 'close': function() {
                     VPLUtil.log('ws close message from jail');
                     ws.close();
-                    var data = {"processid": VPLUtil.getProcessId()};
+                    var data = {"processid": coninfo.processid};
                     VPLUI.requestAction('cancel', '', data, externalActions.ajaxurl, true);
                 }
             };
```

References
---
* **CVE Record**: https://www.cve.org/CVERecord?id=CVE-2024-34312
* **Vendor URL**: https://vpl.dis.ulpgc.es/
* **Fixed Release**: https://github.com/jcrodriguez-dis/moodle-mod_vpl/releases/tag/V4.2.4
* **Commit**: https://github.com/jcrodriguez-dis/moodle-mod_vpl/commit/5faaaf1d01c4088d7c8e3b170dd57c84341cf695
* **CWE**: https://cwe.mitre.org/data/definitions/80.html
File Snapshot

[4.0K] /data/pocs/cc0e6efa96129234c70f61b66b06c9553b6c2a15 └── [5.7K] 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.