Waf vulnerability caused by nginx url Decoding

Source: Internet
Author: User
Tags url decode

This ngx bug was found last year and was not written until recently.
The Nginx ngx_unescape_uri function does not comply with the standard url decode when processing url decode, causing a series of waf
All have bypass vulnerabilities
The function with this problem is located in ngx_unescape_uri (u_char ** dst, u_char ** src, size_t size, ngx_uint_t type) in the Code src \ core \ ngx_string.c)

 

void ngx_unescape_uri(u_char **dst, u_char **src, 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 == '%') {                 state = sw_quoted;                 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; } 

This function discards % if the first character after % is not in hexadecimal range when processing the % code, otherwise, % and the first character are discarded if the second character is not in the hexadecimal range, the specific manifestation is the SQL Injection keyword select. If it is written as s % elect, after ngx encoding, it will become slect to bypass waf filtering rules, for example, IIS asp codes s % elect to select, and % and changes to nd after being decoded by ngx.
Let's take a look at the open-source waf naxsi of OWASP, an internationally renowned web security organization. The problematic code is located in naxsi_src \ naxsi_utils.c.
 


 


 

/* ** Patched ngx_unescape_uri :  ** The original one does not care if the character following % is in valid range. ** For example, with the original one : ** '%uff' -> 'uff' */ void naxsi_unescape_uri(u_char **dst, u_char **src, 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 == '%') {                 state = sw_quoted;                 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++ = '%';             *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 */          *d++ = ch;              break;         }     }  done:      *dst = d;     *src = s; }

From the code above, I have not seen the problem of ngx decoding function and processed it. However, the author of NAXSI only handles the first case, that is, if the first character after "%" is not hexadecimal, "%" is reserved. However, if the first character is, but the second character is not. For example, the s % elect encoding mentioned above will change to slect, so this code still has the problem of code processing malformed Waf rules being bypassed, and many other keywords can be bypassed besides select.
This issue exists in many modules that use nginx decoding code, such as ngx. unescape_uri and ngx. req. get_uri_args in nginx lua.
The standard urldecode code after correction is provided below.

 

voidngx_unescape_uri(u_char **dst, u_char **src, 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;}



For more information, see

Https://code.google.com/p/naxsi/wiki/SecAdvisories
Http://packetstormsecurity.com/files/120960/OWASP-WAF-Naxsi-Bypass.html
Http://seclists.org/bugtraq/2013/Mar/133

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.