Discovering Vulns

by Cliff

"H3y d00Dz w07 R t3h r34l1y k3wl hAx 4...?"

Aren't you just sick of reading this kinda thing?  Guess what, the "k3wl hax" don't get designed and published by Microsoft each week.  People find them.

Where do exploits and vulns (system vulnerabilities) get found?  They're usually bugs or misused features.  But how do they get discovered?  How can you discover your own, or better still, how can you reduce the risk of someone else finding vulns with your code?  I'm going to talk in general terms about methodologies as opposed to any script-kiddie examples.

Exploits

Exploits are vulnerabilities that have been taken to the next level - someone has seen a weakness/vuln and then worked out how to abuse it.

An exploit may allow illegal code to be run, it may just crash a system, or it may open a back door for further abuse later.  Exploits are pretty much limited by the vulnerability found, but sometimes what appears a minor vulnerability can open up a chain of exploits.

Some types of exploits are described below:

Reboot:  Make the server require a restart.  This can interrupt other processes, maybe require manual starts of some tools, cause a lot of anxiety, "stability" issues, and other bad things.  Very hard to track down.

Starve of Oxygen:  Strangle all the other apps on the box.  If apps run out of system resources (typically RAM or disk), they can get panicky and start throwing errors of their own.  Starving a box using one vuln/exploit may force other apps to fail, possibly revealing secrets along the way, or at least being a huge pain to clear up.

Slow to Crawl:  If all the starved apps above behave well, they'll just starve to death, and the server will spend every CPU cycle dealing with error messages from dying applications.

Reveal a Secret:  We just had the one-hundred-millionth (that's a huge number, 100,000,000 seconds is over three years!) set of customer sensitive data leaked by computer systems in the U.S.  Of course the real number is much higher; these 100 million were the ones that had to be confessed.  Computers hold so many secrets and they're held so insecurely that secret-fishing is a massive exploit.  Secrets could be personal details, or even server details, both valuable to different groups.  If an app under duress will report its database filepath, for instance, other attacks can be crafted to attempt to retrieve that file (and the goodies it contains!).

Run Illegal Code:  The server details are a very useful secret for further exploitation.  Illegal code may run in-process and so widen the hole of the vulnerability by giving escalated privileges.

Open a Door:  Illegal code could be used to install a backdoor into the system, making future breaches easier.

Pwn3d!:  And the box becomes a zombie, completely owned by someone other than the owner!

Failing Inelegantly

Great, you've written the killer app for whatever system/language/etc.

Well done!  You probably started as a proof-of-concept, then added a bit of testing onto the end, then fixed it for the tests that failed, and called it RTM.  There is only one person in the world less qualified to test your code than you are and that's your mother.  You are the world's worst test of your own code.  You know the workflows, you know where the bodies are buried, you know which bits have to be handled gently.

Unfortunately, your users won't.

Users are dumb, all of them.  If they weren't dumb, they'd have written the app themselves, so assume they're dumb.  If you went so far as to provide a manual/training for your app, your users will either forget it or use it as a bible.  But you'll have forgotten one or two key points, so they'll improvise.  They'll put a null in the cost box instead of a zero.  Hell, they may even type "zero".  Likely this will cause your system to fail.  How it fails is critical not just to the app, but to every other system on the machine!

Yum!  Resources!:  If your app fails catastrophically and fails to release resources (memory usually), you're enemy number one.  Exploit:  Crash the app a few times and watch as other systems struggle for oxygen.  One of them may do something cool, or at the very least, force a reboot.

Dog in the Manger:  Your app fails, but in failing pops up a modal dialogue warning of the failure before closing down.  Exploit: similar to above, the program holds server resources hostage until some stupid "O.K." box is ticked... on a blade in a massive server farm!

Debug Messages:  Your app fails, and in order to help you out, it tells you some secrets about where and how it failed.  Now everyone knows what version of .NET (or whatever) you're running and, lookee here, a snippet of the app code.  That could be handy later...

Error Messages:  Like debug messages, but less friendly.  It's quite common to see databases telling you things about themselves when a web app has failed to consider a problem (e.g., MySQL, Access).

You can force inelegant failures by feeding in bad data (remember that user who typed "zero"?  What if it was malicious?!  You may not know how to exploit a vulnerability, but somebody else might, so treat all vulns as serious.

Unexpected Input = Unexpected Output

Applications usually deal in one or another with data.

In fact, if they don't they're probably just cartoons and not worth bothering with.  Data can go into or come out of some kind of datastore, usually a database package of some sort.  This is cool.  It means we may be able to get some secrets out in exchange for putting some weird stuff in (technical name here is SQL injection).

How do you get to enter weird stuff?

Have a look at the app you're testing and start typing things into the fields you can type things into.  The key here is to type in things the application isn't expecting.  Good apps will validate these attacks away, poor ones won't.  Inputs typically expect text, a number or sometimes even a file - don't give them exactly what they're expecting.

If they want a file (e.g., an avatar upload for a forum), try passing them an MP3, or an EXE.  See what happens.  You should have the file rejected straight away, but if the app accepts an EXE, you may find a way to execute it (on the server!) later.

If the app wants a number, what kind of number does it want?  If it expects an integer, try giving it a float (or any other non-integer, such as 3.14159).

What happens if you give it a 0?  Or a 0.000000000000001?  Or -1?  Or 999999 <snip loads more 9s> 99?  Or zero?

One of these tests may upset the system if it tries to insert text into a numeric field, or tries to divide by zero.  If the system is strong, it'll laugh at your efforts.  But lesser apps will trip up and maybe tell you a bit about the system!

If the app expects text, then try giving it loads of text.

Try giving it non-printing characters.  Try giving it characters that have special uses too - my favorites are: ';/&--%*?, spaces, and various combinations of them depending on what I've discovered about the app (if it has an Microsoft SQL back-end, try feeding fields with: %%';--)

This can be fascinating if you get your entered text echoed back to you on the next page (for instance a search form), as if your entry isn't parsed and validated.  You can start building database queries to discover more about the app and possibly release secret data.

Websites may be probed by messing with their query strings if they pass data in the query string (what appears in the address bar).  You may want to try HTML-encoded values.

So what if you hit a web app with massive JavaScript validation?

It may have similar matching validation on the server or the developer may have been lazy.  Try a tool like Tamper Data (a Firefox extension) to tweak exactly what gets posted back to the server after the JavaScript has had its fun and tried to stop you!

Can't Take the Strain

Load testing is the opposite of a DDoS attack.

Proper load testing will let you know how much activity your server/app can handle before melting down using the exact same tools as you could use for a DDoS.  You just watch the results more closely.

Microsoft has a great free stress/load testing application "Web Application Stress Tool" (a.k.a Homer).  Find it on their website or download it here.  They also have a fancier one with some of the datacenter editions of some tools, but Homer will do all you need.  There are doubtless many others available too.

Start off by working out what a "sensible" workflow through your site may be, and record it.  Now play that workflow back with more clients and note which pages seem to be slowest (from the results).  Ramp it up a bit more, keep noting your results, and keep going.

If you graph your results, you'll notice a pretty linear rise in response times until you hit an elbow in the curve where responses set dramatically slower.  This is your theoretical maximum load.  Of course, real world usage isn't nearly so relentless as a cluster on the same LAN hammering one app, but usage will come in peaks, and you must be able to handle those peaks, not the average (including overnight) load!

I'm sure you've found one or two pages of your app which seem to cause you the most delays.  Rewrite them or split them into parts and keep the server load down.  It'll probably be the page with all the big database access/writes, etc., so look at optimizing those.

If testing someone else's site, make sure you have permission first.  One man's load test is another man's DDoS!

Finally

When writing your app, try designing in security from the beginning.

This means coding defensively, expecting your audience to be at best dumb, at worst, hostile!  Validate every field you have both on the server and client, and only accept values within the most restrictive range.

Expect non-alphanumeric characters and the effects they can have.

Trap specific errors, all you can think of, and handle them gracefully.  Always have a catchall for unspecified errors, and again, handle it gracefully.

Get your code read and tested by friends/peers/colleagues (open-source software has a passive testing pool of peers).

Test your app on a virtual machine of some sort (Microsoft Virtual PC or VMware) so you can recover from errors quickly and easily without killing any other apps.

Talk to your datacenter guys about the possibility of using virtual servers (again VMware/ Microsoft both have excellent offerings) to completely ringfence apps.

Always make sure you disable any debug modes you have before going public with your app, and finally load test your app so you know how it will cope over time.

If you know up front that you will run into loading problems in about three months with expected growth, you can plan for app tuning or hardware expansions and make sure you don't starve other apps causing them to fail.

And in all that spare time you now have, why not try finding some new vulns?

Return to $2600 Index