You’ve setup your Burp proxy, you walked through the application, ran some spidering, setup your session configurations, now the scanning begins rockstar, lets see all those vulns. Stop. Let the scanner do its work. Now it’s time to do yours and thoroughly enjoy it. Clear cache and cookies. Make a new user. Spin up a new Burp instance if need be. Savor this moment of simplicity. Tell yourself you’ll only look at the scan results to validate that the scan is running without error. You’ll have time to validate all those red blinking things later.
It all begins with a question?
Yes. Penetration testing is nothing more than a series of questions and answers. We have automated questions, questions that get answered and parsed into pretty interfaces, not so pretty interfaces and everywhere in between. There are questions that we ask our clients about the engagement, questions we ask them about the scope, questions that we ask ourselves before testing. The most important questions during the test window though are the questions to the application itself. You could ask the devs, sure that might work if they had time to respond to your every inquiry/knew what would happen in the first place – I don’t mean to say this isn’t helpful to talk to devs to get more insight though. Most of your questions you should be asking are to the application itself. That may sound absurd. Why would you ask your human formulated questions to an application? Because you’ll begin to see the test for what it really is: A Q&A session between you, your tools, your caffeine intake, and your target.
When you’re asking questions to your target application it’s best to start off simple so you’re not immediately bogged down in details. What is your purpose? Who uses you? What’s this button do (non-technically)? Simply walk through the application and ask your application these questions in the form of GET/POST requests. Go to the sitemap, go to the help page, give it a skim. Go get the answers to the questions you formulate in the responses you see and just be childishly curious. No need to write any of these questions or answers down – no one is a fan of overhead just keep them in the head. Then we ask the really obvious ones everyone asks but are tantamount in importance: What’s stored on this site that’s valuable to an attacker? Passwords? CC numbers? Personally identifiable information? Proprietary information? The client’s reputation? More times than not it’s a combination of most if not all of those – and yes their site source code is probably considered 40% proprietary and 60% Stackoverflow (rough estimate).
Then we get out notepad (or vim or nano or notepad++, or cat >> ./notes, whatever). Now it’s time to record questions that really do need solid answers if it’s possible to obtain them.
What webserver is this? Does it switch at all for certain pages/domains? What OS is this webserver running under? Does it switch at all for certain pages/domains? What is the backend database? What framework are they using? (ignore versions for now, more on that later) Where are they getting/sending their data from/to (external/internal sources) and how? Ok, drop the pen. Save it somewhere and fill it out as you go now. Let’s get back into the pure wetware.
How did you do that and why?
These are just disorganized sample questions – what’s really valuable here is being observant to every parameter and process in every request and noticing change. Notice the small things – don’t be afraid to diff those two seemingly similar looking randomized strings. But when you might see they’re similar but not the same just ask why or how or even better: both. The other part of how is formulating how you might implement it. I don’t mean code it out. Just think for a second how you’d handle a small subset of the logic of the application and focus on it. What would you do to get from A to B. This is where being somewhat of a developer pays off. It will allow you to tap into a reservoir of assumptions the programmer might have made – because your way may have been the correct way. You test to see if your implementations differ and how they differ then perhaps why they do.
A simple real world example observed on a prior engagement: You begin testing a series of 3 POST requests used in the ‘forgot password’ functionality. The first page itself accepts a username. The second the security questions for that user (yes you already see that it’s user enumeration and security question enumeration). And finally the third page resets the password by asking the user to enter in the new password twice to confirm. No emails are sent, by design it’s actually terrible. So lets break it with questions. First you ask how is it confirming my security questions? That’s fairly simple. You test other questions like: is it case sensitive? What happens when I omit the security questions POST’ing to that page and what happens when I try to cause the application to fail by assigning the POST parameter as an array instead of a single string (fail open: ex – answer=catchme). Is it ratelimiting? Or is it requiring a strong CAPTCHA to enter in the security questions to prevent bruteforce? None of this seems to do anything really useful. Failures always redirect back to the security question page with an error stating the answer was incorrect. Well that’s unfortunate. But I’m not done interrogating it. So how is this thing working? First page’s POST posts to itself as do the others. The response when its successful is a redirection to the next page. And the security question page follows similarly. How does the next page know what you entered in the last page? It must be something I’m sending.. namely the cookie and therefore the session. So you test this theory by requesting the questions page itself without cookies. It redirects you to the page that asks for the username. You re-insert the cookie to the same request and observe it asks you for the security questions. Confirmed! Then you begin to wonder what other values are tied to the session, and it hits you: what if the set new password page never checks that I actually entered in the correct security question’s answer and instead only checks the username? You enter in the username into the first POST request, copy the cookie and POST to the third. Violla. A success page indicates you have successfully changed the password. Ouch.
Where are you?
Have you ever noticed your scanner missed a very simple parameter because it simply couldn’t understand the format? Have you ever seen an application scanner waste precious time grinding up against a page that you knew wasn’t going to actually process because it required prior steps to associate the session to the actual logic of what was getting sent to the backend? I have, it’s annoying – sometimes annoying enough to write extensions, but for the most part it’s more beneficial to identify that input or series of inputs and throw it through your own battery of tests either with those machine hands of yours or Burp intruder if you’re into that whole brevity thing.
Let’s talk about delimiters. What are they if not just parameters within parameters? A scanner will treat one GET/POST/cookie/JSON/XML element parameter as a single parameter. But you’re smarter than a scanner. Sometimes it’s beneficial to go look through the parameters and spot delimiters because likely the scanner will have just appended a payload but you! You can put any payload anywhere you please.
So go find the delimiters in this and count the possible parameters, I’ll wait:
Got a number? I didn’t count either. But if you did it’s a good exercise! I’m not pentesting it so I don’t have the time but you might be! It’s important to prioritize and always keep mind of the time afterall (see conclusion). Break down The obvious ones (thanks Burp):
But what about…
These parameters too need love too. Yes I missed a few. The ‘nt’ parameter it should be fairly obvious where we want to break into: likeliest will be those number values themselves perhaps even the parameter names if they cause a nice exception or an interesting stack trace. Now that ‘tl’ parameter has me curious.. how many parts can I break that up into?
Always URL decode, even for hex ninjas it’s easier on the eyes. So these are relatively mundane looking but they serve an illustrative purpose. You have to ask exactly where the inputs are to the logic of the application. Just because some filters are applied to one part of the parameter doesn’t necessarily mean the other part of the parameter will have that filter. Basically what this is getting at is it’s just as important to find where as it is how. Content and input discovery are crucial to give you more attack surface. Don’t overlook trivial things.
Some tips to speed things up:
Hot keys – learn to love them. Any decent RTS player will tell you they aren’t simply a convenience they are a necessity! Try to bind them in such a way so that your left hand can do them easily by itself because it’s likely your right hand will be busy with either the mouse or a coffee mug. They will speed up these repetitive pokes considerably and you’ll be more likely to perform them if they are easier – human nature.
Where do you see yourself in 5 pages?
What’s getting stored in the data structures associated with your session that you control like the sample in the example in the first session or even other user’s session? This doesn’t just apply to finding stored XSS. This is another part of identifying inputs but it’s inputs into the data layer and not simply the first page. How does one parameter carry to other pages and what is reflected back. If it is reflected back is it encoded differently or filtered differently? This may be an indication that they’re sanitizing output on some pages but not performing proper input filtering. Scanners have a very difficult time observing these types of bugs because they’re mostly just focused on the response of the immediate request. Every single input that gets transmitted to another user, sent over email, posted to another site, or used in other components of the system that should be carefully scrutinized and you’ll quickly realize how many objects this actually is. For every input that you believe will be transmitted just ask where is it going? How is it getting there? Then you get into the myriad of “what if’s”. What if I set my username to me%0aping%20-c%201%20mysite.com%0a when I know they were setting up some limited shell service for me? What if I encoded my username in such a way that it would be equivalent to another user’s account in the authentication component without actually triggering the duplicate user error in the sign up page’s check through a Unicode trick? Where is this data going? The interactions of different components and their technologies sometimes brings forth the nastiest and most lethal of vulnerabilities.
What more can you tell me?
Are you a cat or a mouse? Sometimes you get verbose headers that tell you nearly everything you want to know about a webserver type and its version number and/or the tech stack being used. This is fantastic. You’ve already filled out those questions. But there is more, code re-use is extremely prevalent and not all programmers actually monitor security feeds to spot new CVEs. What if the server is tell you next to nothing about the webserver or frameworks in use in its headers? Tools like httprint are useful but sometimes it’s nice to just do the job manually to determine a webserver or webserver version. Frameworks and libraries used can also be identified. There are so many ways of doing this, this section wont be exhaustive but hopefully it’ll get you on the right track.
There are simple simple ways of identifying a framework based on the parameter names it uses. The most obvious being something like VIEWSTATE which would likely be ASP.NET or JSESSION which would likely be Java and Tomcat. Googling cookie names and parameter names will give you very interesting things to look into. For instance, Apache can be easily identified by requesting /server-status or /status to see a 403 forbidden or a similar non 404 error message. For IIS, I typically check for /trace.axd. For Apache version identification I sometimes poke at individual CVE’s I know are easy to throw like: CVE-2012-0053 – which will narrow it down to 2.2.x through 2.2.21 and give you another finding. These will give some detailed error messages that may help. Any time you see error messages, it’s highly advisable to just copy them put them in quotes and google them as they will likely be in Stackoverflow explaining an existing bug and will help you narrow down the libraries, frameworks, or webservers in use and their associated versions. Sometimes error strings also change from version to version: checkout the SVN or Github of that project and see when the change was made – you now have a ballpark of ranges of versions if you can narrow down when a particular item was changed. To query languages or frameworks in use it’s often necessary to delve a little deeper into the behavior of certain applications. Some apps will accept ‘answers=this’ very simply and not complain, PHP on the other hand will shit itself complaining that the parameter is not of type string or a similar error. It’s extremely important here to fuzz parameters and try to get as many error messages or anomalies as possible. I like fuzzdb but you’ll do well to add to the list of payloads and techniques to identify peculiarities. This is the magic sauce, it can be taught but it’s much more pleasurable and beneficial to gain these over time with lots of tinkering and questions.
The overall question is: What combination of 3rd party libraries/frameworks makes up this application? Go through your request log in the target tab, look for seemingly unique names in URLs like /js/dojo/something.js. Go take a look and then ask the application: how often have you been updated? Check the CVEs against that library and download the library itself. Look for the file structure of the deployment and look for things that might be left behind in those directories: files like VERSION, README, configuration files and the like are especially handy to identify information disclosures. This information in turn can be used to ask further questions about backport patches, what did the devs change from version X to Y in association to this CVE and where can I confirm the vulnerability. You might find default test pages with XSS, debug output from something the developers forgot to delete or even new bugs in the libraries they’re using. The advantage of a lot of open source 3rd party libraries is that you actually have the source code to go confirm some things, and if time permits (or if attack surface is limited to justify some deep dive) research new vulnerabilities in the 3rd party library/framework. Your clients will be thrilled and its also deeply satisfying – particularly googling ‘inurl:’ statements to see how many systems your 0day just popped and giggling like a school girl as you go informing the vendor(s).
Eventually you should get better and better and identifying strings that are unique which make for great google searches. Just keep asking the questions about what is being used and be relentless in your interrogation.
Now what aren’t you telling me?
The little lies in an application that you may notice either with great thought and further probes or even immediately are called assumptions. Do you assume I will go to page X, Y, then Z? What if I went directly to Y first? What about if I went to X established some session variable then went to Z? What if you actually weren’t checking that CSRF token value? What if I omitted it completely? Here is where you simply exhaust attack options. You’ve identified key components, the hows of important things like authentication and parts of session management, maybe you understand a decent portion of their interactions but it’s closing time. Start asking “what if’s” like it’s simply going out of style. The questions you asked the application beforehand might give you some insight about to what to ask next for each particular component you’re checking. Omission is an input in of itself in a way.
Sometimes a little automation is in order, brutally assault the app then ask more questions if abnormalities appear:
(using Burp Intruder to exhaustively go through %00-%ff and observe responses – use hex digit bruteforcer, extracting error code from a page with the ‘grep extract’ feature)
Simple questions such as “what types of characters will this app accept and how does it return them to me afterwards?” can lead to very interesting results if you know where to look for the error code. Often times it’s as simple as content length differences from the norm, occasionally you’ll get error messages. When the app tells you an error message you Google that string in quotes and then you’ve likely answered another question – what exactly are they using and how can I exploit it? I admit a strong reliance on Burp’s toolset. I can’t stress the need to learn Burp Intruder inside and out. It’s a fantastic tool. Learn to sort the responses to your fuzzing, learn to develop your own payloads and learn to grep extract. Response content length is a huge indicator but things like ‘response time’ columns are also just as useful in identifying potential weaknesses. Interrogating through Intruder is that blend between automation and manual tinkering that I find some of the most interesting answers to my questions. Alternatively you can script a lot of these tests that require automation, I find that given the number of test cases against the number of inputs I’m against, it’s often better to hand the automation off to Burp instead of writing up some spaghetti perl/python for each particular situation. Another final tip is _session management : this can be done in Options->Session handling rules. Burp can augment existing tools (proxy through burp and set scope to proxy), make intruder and the scanner more reliable, and overall do some crazy things. More information can be found at http://portswigger.net/burp/help/options_sessions_ruleeditor.html
Be curious, ask questions, google things, poke things, watch things blow up. The real crux and bane to every webapp pentester’s existence though is time. It’s absolutely crucial to keep into consideration the grand picture of things. If you have one day left and your scanner tab has been blinking red the entire time you’ve been doing manual testing? It’s time to put down the manual poking and begin validating/triaging potentially excellent findings. I know I really strayed away from scanner and forbade the use of it but that was more of a point to put the real focus on the manual questioning not the automated ones. Automated scans can be extremely useful to provide more coverage, and its output can often feed back into your existing manual tests and even give you information to answer some of your questions. Hopefully that’s in the form of SQL error messages and the like.