The purpose of this repository is to demonstrate arbitrary code
execution after cloning a repository when using vulnerable versions of
__git_ps1
in two- or three-argument mode.
If you are using bash:
-
Get
git-prompt.sh
from thegit.git
repository (in thecontrib/completion
subdirectory). -
Follow steps 1, 2, and 3b at the top of the
git-prompt.sh
file. -
Clone this repository:
git clone https://github.com/rhansen/clonepwn.git
-
cd
into the newclonepwn
directory.
If you are using a vulnerable version of __git_ps1
(and your
username is username
), you will see the following text in your
prompt:
hello username, you are vulnerable to clonepwn
Otherwise, you will see the following:
$(IFS=_;cmd=echo_hello_$USER,_you_are_not_vulnerable_to_clonepwn;cmd2=sed_-e_s/not.v/v/;$cmd|$cmd2)
The default branch in this repository is not master
—it has an
unusual name:
$(IFS=_;cmd=echo_hello_$USER,_you_are_not_vulnerable_to_clonepwn;cmd2=sed_-e_s/not.v/v/;$cmd|$cmd2)
This name is also valid shell code. Old versions of the __git_ps1
function set PS1
(the variable that holds your prompt) in a way that
causes the code to be interpreted by the shell. This causes the
following to happen:
-
The shell sets the
IFS
variable to_
. This causes the shell to break words with underscores into multiple fields. This makes it possible to pass arguments to commands (Git does not permit whitespace in branch names). -
The shell sets the
cmd
variable to:echo_hello_username,_you_are_not_vulnerable_to_clonepwn
-
The shell sets the
cmd2
variable to:sed_-e_s/not.v/v/
-
The shell runs
$cmd|$cmd2
. BecauseIFS
is set to an underscore, this gets expanded like:echo hello username, you are not vulnerable to clonepwn|sed -e s/not.v/v/
This runs the
echo
command with the argumentshello
,username,
,you
,are
,not
,vulnerable
,to
, andclonepwn
, which, as you might expect, prints the following string:hello username, you are not vulnerable to clonepwn
The pipe symbol (
|
) tells the shell to feedecho
's output to thissed
command:sed -e s/not.v/v/
Those arguments to
sed
cause it to replacenot v
withv
(it removes the wordnot
), and print the result:hello username, you are vulnerable to clonepwn
-
The shell captures the above output of
sed
(because of the$(...)
construct), and the entire$(...)
string is replaced with:hello username, you are vulnerable to clonepwn
-
__git_ps1
shows the above string as the branch name instead of the true branch name.
Note that the above code is benign, but it could have been malicious.
For example, if the branch had been named
$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)
then some real damage could have
been done (erase your hard drive).
The version of __git_ps1
that comes with Git v1.9.3 and later have
been fixed. If you are using an older version, apply the following
two patches to git-prompt.sh
:
- the fix
- the fix to the fix (the fix introduced a regression for zsh users; this patch fixes that regression)
You may be interested in the mailing list thread where this fix was discussed.