From 69bd0dc4beed0ae8fffe09abc80189115155a795 Mon Sep 17 00:00:00 2001 From: moozzyk Date: Wed, 1 Jun 2016 14:19:17 -0700 Subject: [PATCH] Reject requests that have null characters in path --- .../Internal/Http/UrlPathDecoder.cs | 6 ++++ .../RequestTests.cs | 1 - .../BadHttpRequestTests.cs | 30 +++++++++++++++++++ .../EngineTests.cs | 28 +++++++++++++++++ 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/UrlPathDecoder.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/UrlPathDecoder.cs index 7ce0ce8990..5b639fe3c0 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/UrlPathDecoder.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/UrlPathDecoder.cs @@ -64,6 +64,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http // preserves the original head. if the percent-encodings cannot be interpreted as sequence of UTF-8 octets, // bytes from this till the last scanned one will be copied to the memory pointed by writer. var byte1 = UnescapePercentEncoding(ref reader, end); + + if (byte1 == 0) + { + throw new BadHttpRequestException("The path contains null characters."); + } + if (byte1 == -1) { return false; diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs index 6f4f3a2d45..e269fe21f0 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs @@ -138,7 +138,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { app.Run(async context => { - var connection = context.Connection; await context.Response.WriteAsync("hello, world"); }); }); diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/BadHttpRequestTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/BadHttpRequestTests.cs index 77a6db674f..b566c6e488 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/BadHttpRequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/BadHttpRequestTests.cs @@ -189,6 +189,36 @@ namespace Microsoft.AspNetCore.Server.KestrelTests } } + [Theory] + [InlineData("\0")] + [InlineData("%00")] + [InlineData("/\0")] + [InlineData("/%00")] + [InlineData("/\0\0")] + [InlineData("/%00%00")] + [InlineData("/%C8\0")] + [InlineData("/%E8%00%84")] + [InlineData("/%E8%85%00")] + [InlineData("/%F3%00%82%86")] + [InlineData("/%F3%85%00%82")] + [InlineData("/%F3%85%82%00")] + [InlineData("/%E8%85%00")] + [InlineData("/%E8%01%00")] + public async Task BadRequestIfPathContainsNullCharacters(string path) + { + using (var server = new TestServer(context => { return Task.FromResult(0); })) + { + using (var connection = server.CreateConnection()) + { + await connection.SendEnd( + $"GET {path} HTTP/1.1", + "", + ""); + await ReceiveBadRequestResponse(connection); + } + } + } + private async Task ReceiveBadRequestResponse(TestConnection connection) { await connection.Receive( diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs index c2b1a7aa37..1c9eefb324 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs @@ -1170,5 +1170,33 @@ namespace Microsoft.AspNetCore.Server.KestrelTests } } } + + [Theory] + [InlineData("/%%2000", "/% 00")] + [InlineData("/%25%30%30", "/%00")] + public async Task PathEscapeTests(string inputPath, string expectedPath) + { + using (var server = new TestServer(async httpContext => + { + var path = httpContext.Request.Path.Value; + httpContext.Response.Headers["Content-Length"] = new[] {path.Length.ToString() }; + await httpContext.Response.WriteAsync(path); + })) + { + using (var connection = server.CreateConnection()) + { + await connection.SendEnd( + $"GET {inputPath} HTTP/1.1", + "", + ""); + await connection.ReceiveEnd( + "HTTP/1.1 200 OK", + $"Date: {connection.Server.Context.DateHeaderValue}", + $"Content-Length: {expectedPath.Length.ToString()}", + "", + $"{expectedPath}"); + } + } + } } }