diff --git a/HTTPRequest.cpp b/HTTPRequest.cpp index 4022878..8d758c2 100644 --- a/HTTPRequest.cpp +++ b/HTTPRequest.cpp @@ -104,6 +104,24 @@ namespace coreutils { return Status::COMPLETE; } int contentLength = contentLengthHeader.asInteger(); + // asInteger() accumulates digits into a plain 32-bit int with no + // overflow check - a Content-Length long enough to overflow it + // (confirmed live via real scanner/bot traffic: a request for + // "/sra_{...}/' claiming "Content-Length: 18446744073709551615", + // a classic SSTP vulnerability-probe pattern) silently wraps to a + // garbage value, observed as -1. That negative value then passed + // the "(int)buffer.getLength() < contentLength" check below for + // every real buffer length (nothing is ever less than -1), so + // execution fell through to "ZString(buffer.getCursor(), + // contentLength)" with a negative length - reinterpreted as a + // huge size_t, this read far past the real buffer and corrupted + // the heap, crashing (sometimes immediately, sometimes much + // later, in a wholly unrelated MString's destructor) on every + // production apiserver this scanner traffic reached. Rejecting + // a negative Content-Length here, before it is ever used, closes + // this off at the only place that actually needs to care. + if (contentLength < 0) + throw coreutils::Exception("HTTPRequest: invalid Content-Length."); MString contentType = getHeader("Content-Type"); if (contentType.startsWith("application/x-www-form-urlencoded") || contentType.startsWith("multipart/form-data")) {