OhMyZsh dotenv Remote Code Execution

- 4 mins

Abstract

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


Background

OhMyZsh is a highly popular framework for managing ZSH configuration. When 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 automate tasks along with my scripts and dotfiles.

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

According to the documentation:

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

The 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 three 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 uses 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 with 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, working with this material leads to 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 to be allowed. Users can ensure 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 session outcome 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