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_char **src, 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_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; }