Lucene search

K
securityvulnsSecurityvulnsSECURITYVULNS:DOC:29372
HistoryMay 06, 2013 - 12:00 a.m.

Report OWASP WAF Naxsi bypass Vulnerability

2013-05-0600:00:00
vulners.com
33

OWASP WAF Naxsi bypass Vulnerability

Certain unspecified input is not properly handed in
naxsi_src/naxsi_utils.c naxsi_unescape_uri(u_char dst, u_charsrc,
size_t size, ngx_uint_t type) before being used to filtered. This can
be exploited to bypass some WAF rules.

Naxsi site
https://code.google.com/p/naxsi/

Affected
All the version

My site
http://safe3.com.cn/

My nick name is Safe3

It happens like that,the naxsi_unescape_uri function process the % url
decode,if the next char after the % is a hex char and not after the
hex char,then it will drop the % and the next char.So if we input a
sql keyword "s%elect",it will come to "slect" instead,this is not the
standard url decode way.Such as the IIS asp,it will process the
"s%elect" as a result of "select",so we can bypass some
WAF rules just like that.

I afford a standard url decode function patch as the follow to fix this issue:
void
ngx_unescape_uri(u_char dst, u_charsrc, size_t size, ngx_uint_t type)
{
u_char *d, *s, ch, c, decoded;
enum {
sw_usual = 0,
sw_quoted,
sw_quoted_second
} state;

d = *dst;
s = *src;

state = 0;
decoded = 0;

while (size--) {

    ch = *s++;

    switch (state) {
    case sw_usual:
        if (ch == '?'
            && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
        {
            *d++ = ch;
            goto done;
        }

        if (ch == '%'&&size>1) {
            ch=*s;
            c = (u_char) (ch | 0x20);
            if ((ch >= '0' && ch <= '9')||(c >= 'a' && c <= 'f')) {
            ch=*(s+1);
            c = (u_char) (ch | 0x20);
            if ((ch >= '0' && ch <= '9')||(c >= 'a' && c <= 'f')) {
            state = sw_quoted;
            break;
            }
            }
            *d++ = '%';
            break;
        }

        if (ch == '+') {
            *d++ = ' ';
            break;
        }

        *d++ = ch;
        break;

    case sw_quoted:

        if (ch >= '0' && ch <= '9') {
            decoded = (u_char) (ch - '0');
            state = sw_quoted_second;
            break;
        }

        c = (u_char) (ch | 0x20);
        if (c >= 'a' && c <= 'f') {
            decoded = (u_char) (c - 'a' + 10);
            state = sw_quoted_second;
            break;
        }

        /* the invalid quoted character */

        state = sw_usual;

        *d++ = ch;

        break;

    case sw_quoted_second:

        state = sw_usual;

        if (ch >= '0' && ch <= '9') {
            ch = (u_char) ((decoded << 4) + ch - '0');

            if (type & NGX_UNESCAPE_REDIRECT) {
                if (ch > '%' && ch < 0x7f) {
                    *d++ = ch;
                    break;
                }

                *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);

                break;
            }

            *d++ = ch;

            break;
        }

        c = (u_char) (ch | 0x20);
        if (c >= 'a' && c <= 'f') {
            ch = (u_char) ((decoded << 4) + c - 'a' + 10);

            if (type & NGX_UNESCAPE_URI) {
                if (ch == '?') {
                    *d++ = ch;
                    goto done;
                }

                *d++ = ch;
                break;
            }

            if (type & NGX_UNESCAPE_REDIRECT) {
                if (ch == '?') {
                    *d++ = ch;
                    goto done;
                }

                if (ch > '%' && ch < 0x7f) {
                    *d++ = ch;
                    break;
                }

                *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
                break;
            }

            *d++ = ch;

            break;
        }

        /* the invalid quoted character */

        break;
    }
}

done:

*dst = d;
*src = s;

}