In Part 3 of our Hunting for Web shells series, Aaron Williams, Cyber Security Analyst looks at additional methods for detecting Web shells. If you missed part 1 of this series, you can find it here.
HUNTING FOR WEB SHELLS
As mentioned in Part 2, String Matching can be easily defeated by string obfuscation. During our journey trying to detect web shells, we regularly came across files like the example below, which defeated string manipulation by utilising the str_replace function to deobfuscate strings of known bad function calls like base64_decode.
The example above used multiple str_replace function calls to rebuild the strings needed for the web shell.
One example is the line
Which, when executed becomes
$b = create_function
Create_function is part of our blacklisted words list that we String Match on. However, we will never find this create_function with simple string matching because the string is built dynamically during execution.
A fix for this is to look for str_replace functions inside files whilst we are scanning and then actually do the str_replace ourselves to deobfuscate any blacklisted words.
We can then run our regular String Matching process over the deobfuscated file contents, and if we get any extra hits, we can be fairly certain we found a web shell.
After running such a solution over the previous file, we receive the following results from a String Matching scan:
- Catches sneaky str_replace string obfuscation that is able to fool regular string matching
- Only covers one string obfuscation method, more still exist
Whilst developers are not strictly required to adhere to them, Coding Style Practices dictate that line length should be limited. Usually, this falls in the ballpark of 80-120 characters per line. Attackers, however, regularly drop entire encoded/encrypted payloads on a single line to be stored in a variable for later use.
In the previous example picture taken from a real web shell, the variable $Wcore contains encoded text that spans 54,000 characters in a single line.
In theory, this should make finding these kinds of web shells as simple as looking for any file with a line that is more than 120 characters long. In practice, developers sometimes go well beyond the recommended character limit for lines and False Positives (although infrequent enough) are still a thing to deal with. The following example is a WordPress plugin that has a line with 3611 characters.
- False positives are fairly low and usually pretty easy to quickly identify
- Catches sneaky compressed/encoded payloads if the attackers don’t line-break them
- Very targeted detection method that will only catch a smaller subset of web shells
An evasion method to the previous Long Line detection is to just break up your payload over multiple lines.
A public obfuscation tool HideShell does exactly this and is able to bypass many web shell detection tools as a result. Here is a snippet of the resulting file after using HideShell to obfuscate a web shell.
This sequence continues for another 67,000 lines. The line length detection has been bypassed, but now we have a variable that we have added to repeatedly. This is something we can detect on.
With this knowledge, we can scan over the contents of a file and count how many times each variable is used within the file. If a variable is used hundreds or even thousands of times, we can assume we found a web shell and alert.
So far, we have covered just a few methods that are capable of detecting web shells.
As time goes on ParaFlare will continue to add detection methods to this blog post and the accompanying web shell hunting tool. Our goal is to eventually cover most obfuscators and a larger set of languages that web shells are written in.
To find the detection tool we’ve developed head to our Github repository: ParaFlare’s Public Github
Thanks for Reading!
Hide web shells