CVE-2019-11072: Integer Overflow or Wraparound (CWE-190)
value: lighttpd before 1.4.54 has a signed integer overflow, which might allow remote attackers to cause a denial of service (application crash) or possibly have unspecified other impact via a malicious HTTP GET request, as demonstrated by mishandling of /%2F? in burl_normalize_2F_to_slash_fix in burl.c. NOTE: The developer states "The feature which can be abused to cause the crash is a new feature in lighttpd 1.4.50, and is not enabled by default. It must be explicitly configured in the config file (e.g. lighttpd.conf). Certain input will trigger an abort() in lighttpd when that feature is enabled. lighttpd detects the underflow or realloc() will fail (in both 32-bit and 64-bit executables), also detected in lighttpd. Either triggers an explicit abort() by lighttpd. This is not exploitable beyond triggering the explicit abort() with subsequent application exit.
CWE description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
CVSS v3 base score: 9.8
Published: 2019-04-10T22:29Z
Repository: https://github.com/lighttpd/lighttpd1.4
Language: C
Files changed: src/burl.c, src/t/test_burl.c
Commit date: 2019-04-10 11:36:28 -0400
Commit message: [core] fix abort in http-parseopts (fixes #2945)

fix abort in server.http-parseopts with url-path-2f-decode enabled

(thx stze)

x-ref:
  "Security - SIGABRT during GET request handling with url-path-2f-decode enabled"
  https://redmine.lighttpd.net/issues/2945

Diff: diff --git a/src/burl.c b/src/burl.c
index 51182628..c4b928fd 100644
--- a/src/burl.c
+++ b/src/burl.c
@@ -250,12 +250,14 @@ static int burl_normalize_2F_to_slash_fix (buffer *b, int qs, int i)
             s[j] = '/';
             i+=2;
         }
     }
     if (qs >= 0) {
-        memmove(s+j, s+qs, blen - qs);
-        j += blen - qs;
+        const int qslen = blen - qs;
+        memmove(s+j, s+qs, (size_t)qslen);
+        qs = j;
+        j += qslen;
     }
     buffer_string_set_length(b, j);
     return qs;
 }
 
diff --git a/src/t/test_burl.c b/src/t/test_burl.c
index 7be9be50..f7a16815 100644
--- a/src/t/test_burl.c
+++ b/src/t/test_burl.c
@@ -95,10 +95,12 @@ static void test_burl_normalize (void) {
   #endif
 
     flags |= HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE;
     run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b?c=/"), CONST_STR_LEN("/a/b?c=/"));
     run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a/b?c=%2f"), CONST_STR_LEN("/a/b?c=/"));
+    run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("%2f?"), CONST_STR_LEN("/?"));
+    run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%2f?"), CONST_STR_LEN("//?"));
     run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a%2fb"), CONST_STR_LEN("/a/b"));
     run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a%2Fb"), CONST_STR_LEN("/a/b"));
     run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a%2fb?c=/"), CONST_STR_LEN("/a/b?c=/"));
     run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/a%2fb?c=%2f"), CONST_STR_LEN("/a/b?c=/"));
     flags &= ~HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE;

Vulnerable code:         memmove(s+j, s+qs, blen - qs);
        j += blen - qs;
Fixed code:         const int qslen = blen - qs;
        memmove(s+j, s+qs, (size_t)qslen);
        qs = j;
        j += qslen;
    run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("%2f?"), CONST_STR_LEN("/?"));
    run_burl_normalize(psrc, ptmp, flags, __LINE__, CONST_STR_LEN("/%2f?"), CONST_STR_LEN("//?"));