[Snort-sigs] Generic SQL injection false positives

Matt Olney molney at ...435...
Tue Jan 26 16:50:28 EST 2010


Thanks to the hard work of Shong, one of our emerging stars on the
analyst team these are among the changes in this week's update:

Updated rules:
13512 <-> SQL generic sql exec injection attempt - GET parameter
(sql.rules, High)
13513 <-> SQL generic sql insert injection atttempt - GET parameter
(sql.rules, High)
13514 <-> SQL generic sql update injection attempt - GET parameter
(sql.rules, High)
13990 <-> SQL union select - possible sql injection attempt - GET
parameter (sql.rules, Medium)

Thanks for the heads up on these, keep letting us know if you have any issues.

Matt

On Fri, Jan 8, 2010 at 12:20 PM, Matt Olney <molney at ...435...> wrote:
> First,
>
> I wanted to let you know this is still on my plate, but I just haven't
> gotten to it yet.  I have not forgotten about it though.
>
> Second, I sent this email, and it was meant to have been copied to the
> list (but I failed), so here is the info:
>
> OK, here is how PCRE works...it addresses whatever buffer you tell it
> to.  It looks at the exact same buffer data that the content match
> work on.  In fact, if you use the /R flag, you will start your PCRE
> work at the DOE pointer (that is, the end of the last successful
> content match, PCRE or byte_jump).  Here is the switch code from
> sp_pcre.c:
>
>    while(*opts != '\0') {
>        switch(*opts) {
>        case 'i':  compile_flags |= PCRE_CASELESS;            break;
>        case 's':  compile_flags |= PCRE_DOTALL;              break;
>        case 'm':  compile_flags |= PCRE_MULTILINE;           break;
>        case 'x':  compile_flags |= PCRE_EXTENDED;            break;
>
>            /*
>             * these are pcre specific... don't work with perl
>             */
>        case 'A':  compile_flags |= PCRE_ANCHORED;            break;
>        case 'E':  compile_flags |= PCRE_DOLLAR_ENDONLY;      break;
>        case 'G':  compile_flags |= PCRE_UNGREEDY;            break;
>
>            /*
>             * these are snort specific don't work with pcre or perl
>             */
>        case 'R':  pcre_data->options |= SNORT_PCRE_RELATIVE; break;
>        case 'U':  pcre_data->options |= SNORT_PCRE_HTTP_URI; break;
>        case 'B':  pcre_data->options |= SNORT_PCRE_RAWBYTES; break;
>        case 'P':  pcre_data->options |= SNORT_PCRE_HTTP_BODY;  break;
>        case 'O':  pcre_data->options |= SNORT_OVERRIDE_MATCH_LIMIT; break;
>        case 'H':  pcre_data->options |= SNORT_PCRE_HTTP_HEADER;  break;
>        case 'M':  pcre_data->options |= SNORT_PCRE_HTTP_METHOD;  break;
>        case 'C':  pcre_data->options |= SNORT_PCRE_HTTP_COOKIE;  break;
>
> The top two sets are your standard PCRE options.  The bottom calls are
> the Snort specific ones.  In this case, if you wanted to work on the
> HTTP_URI buffer you would have something to the effect of
> pcre:/\?.+SELECT/Ui.  Since you would be in the uri, you wouldn't have
> to worry about line breaks.
>
> As to evasion cases, we could work through them with SO rules, but I
> wouldn't take the overhead hit on that for a generic detection rule.
> My goal in rewriting these will be to get the performance right, catch
> your standard sql inject statements, and handle those evasion cases I
> can.  I may go ahead and throw together some rules that looks to
> detect some of the evasion cases you are talking about.
>
> If you guys have specific pcaps you want me to include in testing,
> feel free to send them over.
>
> Matt
>
> On Tue, Dec 29, 2009 at 9:03 PM, Guise McAllaster
> <guise.mcallaster at ...2420...> wrote:
>> My understanding is that the pcre directives will match against the
>> current data buffer (how large is it? I don't know but probably a
>> config setting).  I could be wrong and it behaves like normal pcre
>> where it will match only on a single line (i.e. data separated by
>> newline character(s)) unless the 'm' (multi-line) modifier is used
>> (e.g. "/select.*from/m").  SourceFire, please clarify if possible.
>> (Thank you.)
>>
>> Nevertheless, your pcre is still flawed since it is anchored at the
>> beginnings and ends of the buffer (or line whichever is the case).
>> Perhaps you mean to use words boundaries.  Something like:
>>
>> pcre:"/\bupdate\b";
>>
>> Hope these help.
>>
>> Guise
>>
>> P.S. SourceFire has already admitted that things like "+" or "/**/"
>> are not removed from the normalized buffer so you are correct, they
>> can be used to trivially bypass snorts.
>>
>>
>>
>>
>> On 12/29/09, Paul Schmehl <pschmehl_lists at ...3425...> wrote:
>>> OK, if you change the rule to use uricontent instead of content, then
>>> you'll avoid missing content that will appear after being normalized.
>>> However, I'm not convinced that normalizing will strip out sql comments
>>> like /**/.  If I'm correct in that, then even uricontent:'update"; nocase;
>>> pcre:"/^update$/i" will miss things like UP/**/DATE.  If uricontent
>>> doesn't match, pcre will never be tested, because content/uricontent
>>> matches are linear and from left to right.  The first content/uricontent
>>> must match something in the packet or the rest of the rule will be ignored.
>>>
>>> Anchoring the sql query syntax (e.g. pcre:"/^update$/i"; forces a match on
>>> only that word and no others.  ISTM that would be what you want if you're
>>> trying to catch sql injection and avoid false positives.
>>>
>>> --On December 29, 2009 9:28:35 AM -0600 Guise McAllaster
>>> <guise.mcallaster at ...2420...> wrote:
>>>
>>>> Sir, let me clarify a few thing.  Firstly, "content" matches will not
>>>> match against a normalized buffer so you are correct that data such as
>>>> "D/**/ROP, DR/**/OP or DRO/**/P" will bypass a content match looking for
>>>> "DROP".  However, using uricontent will match the normalized buffer
>>>> which should (hopefully -- this is what we need clarifications on as to
>>>> what specific the normalization is) have removed such things as "%20",
>>>> "+", and "/**/".
>>>>
>>>> Now, as for your comments, I am confused.  You say, "If you use
>>>> content:"foo"; nocase; first, and then pcre:"/^foo$/i"; next, content
>>>> will never match, so pcre will never be checked."  Yet data containing
>>>> "foo" will match the content check and snort will move on to chech the
>>>> PCRE match.  Howevers, the PCRE is not correctly what you want I
>>>> think.  It will only match "foo" and nothing else (e.g.
>>>> "<beginning_of_line>foo<end_of_line>").  For example, "0foo", "bfoo",
>>>> "foobar", and "foosball", will not match.
>>>>
>>>> As an aside, thank you Matt and VRT for looking in to these rules as
>>>> they are a mountain of false positives in my environment and thus not
>>>> useful in the currently.
>>>>
>>>> Guise
>>>>
>>>>
>>>> On Tue, Dec 29, 2009 at 2:50 AM, Paul Schmehl <pschmehl_lists at ...3450.....>
>>>> wrote:
>>>>
>>>> Now that I've had some time to think about this, I do not think that
>>>> normalization will remove these.  I suspect that they will be passed to
>>>> the sql server.
>>>>
>>>> The problem with trying to detect them is this.  If you use
>>>> content:"foo"; nocase; first, and then pcre:"/^foo$/i"; next, content
>>>> will never match, so pcre will never be checked.  But to catch every
>>>> possible instance you would have to try to match on the /**/ first, then
>>>> strip it from the content and match on update.  I don't think snort can
>>>> do that.
>>>>
>>>> To bypass detection, I could use any one of the following: D/**/ROP,
>>>> DR/**/OP or DRO/**/P.  How would you test for all those instances?  In
>>>> a simple rule that's designed to detect "generic" sql injection, I think
>>>> you stick with detecting update and set.
>>>>
>>>> If you want to catch instances of comments inserted into sql injection,
>>>> you would need a separate rule that attempts to detect the evasion.
>>>> Considering that urls normally have forward slashes in them, that would
>>>> not be easy to do.
>>>>
>>>>
>>>>
>>>>
>>>> --On December 28, 2009 6:40:42 PM -0600 Paul Schmehl
>>>> <pschmehl_lists at ...3425...> wrote:
>>>>
>>>>
>>>> I believe normalization will remove those as well, but someone from
>>>> Sourcefire will have to confirm that.
>>>>
>>>> --On December 29, 2009 12:15:53 AM +0000 Guise McAllaster
>>>> <guise.mcallaster at ...2420...> wrote:
>>>>
>>>>
>>>> Sure:
>>>>
>>>> http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/
>>>>
>>>> Search for "/**/"
>>>>
>>>> A good point somebody says is that we need to know what exactly the
>>>> URL normalization is done so we can know what it eliminates.  Some
>>>> like "%20" and "+" or "++" are sure recognized but others?  What are
>>>> they?
>>>>
>>>> Snort has been victim to some bypasses in the past (no offense, VRT).
>>>>
>>>> Guise
>>>>
>>>> On 12/28/09, Paul Schmehl <pschmehl_lists at ...3425...> wrote:
>>>>
>>>> Can you provide an example of that?
>>>>
>>>> --On December 28, 2009 4:15:20 PM -0600 Guise McAllaster
>>>> <guise.mcallaster at ...2420...> wrote:
>>>>
>>>>
>>>>
>>>> From what I've seen, some SQLi will work using "/**/" instead of
>>>> spaces.  Other bypasses are possible as well I thinks.  Others want to
>>>> contribute some useful bypasses to spaces?
>>>>
>>>> Guise
>>>>
>>>> On 12/28/09, Paul Schmehl <pschmehl_lists at ...3425...> wrote:
>>>>
>>>> --On December 28, 2009 12:10:37 PM -0600 Matt Olney
>>>> <molney at ...435...> wrote:
>>>>
>>>>
>>>> I see a lot of false positive for generic SQL injection rules.  For
>>>> example, SID 13514 shown here:
>>>>
>>>> alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"SQL
>>>> generic sql update injection attempt"; flow:established,to_server;
>>>> content:"update"; nocase; pcre:"/update[^\n]*set/i"; metadata:policy
>>>> security-ips drop, service http;
>>>> reference:url,www.securiteam.com/securityreviews/5DP0N1P76E.html;
>>>> classtype:web-application-attack; sid:13514; rev:4;)
>>>>
>>>> Alas it alerts for normal traffic like this:
>>>>
>>>> GET /get_updates_1/assessment/frameset_yellow.asp  HTTP/1.1
>>>>
>>>>
>>>> I don't see how a sql injection attempt is going to begin with any
>>>> character other than a space preceding it.  How would the sql engine
>>>> be able to parse that?  ISTM that the update could simply be anchored
>>>> on both sides; e.g pcre:"$update^/i";  For update to work, the only
>>>> thing that can be on either side of it is a non-alpha character or a
>>>> single quote, which the sql parser will discard.  If you want to
>>>> include set (which makes sense), I would make it a separate
>>>> detection.  A typical update statement would be UPDATE table SET
>>>> blah='foo' where blah='bar' or blah like '%doo%';
>>>>
>>>> Something like this would be better, in my opinion.
>>>>
>>>> alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"SQL
>>>> generic sql update injection attempt"; flow:established,to_server;
>>>> content:"update"; nocase; pcre:"/$update^/i"; content:"set"; nocase;
>>>> pcre:"/$set^/i"; metadata:policy security-ips drop, service http;
>>>> reference:url,www.securiteam.com/securityreviews/5DP0N1P76E.html;
>>>> classtype:web-application-attack; sid:13514; rev:5;)
>>>>
>>>> Mind you, I haven't tested it, but it would certainly eliminate the
>>>> false positive given in the example.
>>>>
>>>> Paul Schmehl, If it isn't already
>>>> obvious, my opinions are my own
>>>> and not those of my employer.
>>>> ******************************************
>>>> WARNING: Check the headers before replying
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> -- ------- This SF.Net email is sponsored by the Verizon Developer
>>>> Community Take advantage of Verizon's best-in-class app development
>>>> support A streamlined, 14 day to market process makes app
>>>> distribution fast and easy Join now and get one step closer to
>>>> millions of Verizon customers http://p.sf.net/sfu/verizon-dev2dev
>>>> _______________________________________________
>>>> Snort-sigs mailing list
>>>> Snort-sigs at lists.sourceforge.net
>>>> https://lists.sourceforge.net/lists/listinfo/snort-sigs
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> Paul Schmehl, If it isn't already
>>>> obvious, my opinions are my own
>>>> and not those of my employer.
>>>> ******************************************
>>>> WARNING: Check the headers before replying
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> Paul Schmehl, If it isn't already
>>>> obvious, my opinions are my own
>>>> and not those of my employer.
>>>> ******************************************
>>>> WARNING: Check the headers before replying
>>>>
>>>>
>>>>
>>>>
>>>> Paul Schmehl, If it isn't already
>>>> obvious, my opinions are my own
>>>> and not those of my employer.
>>>> ******************************************
>>>> WARNING: Check the headers before replying
>>>>
>>>>
>>>>
>>>
>>>
>>>
>>> Paul Schmehl, If it isn't already
>>> obvious, my opinions are my own
>>> and not those of my employer.
>>> ******************************************
>>> WARNING: Check the headers before replying
>>>
>>>
>>
>> ------------------------------------------------------------------------------
>> This SF.Net email is sponsored by the Verizon Developer Community
>> Take advantage of Verizon's best-in-class app development support
>> A streamlined, 14 day to market process makes app distribution fast and easy
>> Join now and get one step closer to millions of Verizon customers
>> http://p.sf.net/sfu/verizon-dev2dev
>> _______________________________________________
>> Snort-sigs mailing list
>> Snort-sigs at lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/snort-sigs
>>
>




More information about the Snort-sigs mailing list