In Depth: Pentesting Laravel part 3 - Looking for "Interesting" Code
[In Depth #29] It's time to spend some time looking for smelly or suspicious code, searching for common patterns and functions that usually show up around weaknesses. 🕵️
If you've missed any of the previous parts, go check those out first:
Part 1: Passive Scans
Part 2: Configs, Dependencies, and Routes
Part 3: Looking for "Interesting" Code
Part 4: Reading Code Pays Off!
Once I've worked through all the major structural components (as we did in part 2), the next step is to look for common indicators of vulnerable code. I sometimes refer to this step as my "heuristic searches", although it would be more accurate to say: "a bunch of regular expressions that flag potentially interesting code", but "heuristic" is shorter and sounds fancier (although is harder to spell!).
The "interesting code" I'm looking for here is code that is either:
- obviously vulnerable
- part of a bigger vulnerability
- looks safe but feels "wrong"
If you're not sure what I mean with #3, consider the term "code smell". We often use it for buggy or needlessly complicated code that is likely to cause problems later, and the more experience we get as developers, the more of a sense we have for dodgy code feels like. I get the same feeling with potentially vulnerable code.
Sometimes a piece of code just feels wrong, and although it looks OK on it's own, I'll do a bit of digging, and will often find a weakness or vulnerability to be exploited (or at least reported). These are often more obscure or serious vulnerabilities, as they lead to interesting places and are easily overlooked.
The most common example I come across is SQL Injection (SQLi). I'll often find raw SQL queries with user input injected straight into the query (i.e. no parameterisation), but the user input is passed through a validator that unintentionally blocks special characters.
It doesn't matter that the code is technically safe, there is still an SQLi vulnerability waiting to be exploited. All it would take is for the validator to change slightly.
Running My Searches
My searches consist of a series of regular expressions that I use within PhpStorm across the entire codebase. Some of them are incredibly noisy, and can produce hundreds or even thousands of hits on a large codebase, while others are very selective. It depends entirely on the app and how it's built, and what it does.
The important thing to stress here is that this is intentional. I want these searches to find everything, and rely on me eyeballing the results - rather than try to refine them down to eliminate the noise. It's easy to refine a search too much and miss something subtle, and the point of what I do is to try and find the subtle things.
I run my searches in PhpStorm, which lets me open the results in a tab and click through them easily. I also discovered recently you can pin results and do other searches without losing your previous results, which I was very excited to learn! I also make a lot of use of "Go to Declaration/Usages" to easily jump around in the code.
Regular Expression Format
You'll notice a bunch of my searches follow this format:
\b(function|another_function)\s*\(
Which we can visualise with Regexper:
Essentially, we're looking for whole words, i.e. function names, before optional whitespace, before a left bracket. Or to put simply: calling a function/method.
This isn't bulletproof, but does a good job of finding instances of functions in various coding styles. That said, if you have any suggestions to improve my regexes, let me know!
Alright, that's enough background notes... let's run our first search!
Any RCEs?
At the top of my list is a search for any functions that make Remote Code Execution (RCE) easy:
\b(eval|system|exec|passthru|shell_exec|assert|(Console|Facades|Component)\\Process)\s*\(
Here it is in PhpStorm:
Three hits, but all of them are within a compiled javascript file, so we can ignore them.
This is pretty normal - most sites don't use those functions. In my experience RCEs aren't overly common Laravel apps, because Laravel gives us the tools to do so much already.
If this did find any results, I would be taking a very close look at the code to figure out if anything comes from user input that could be exploitable here. Sometimes I get lucky... 😈