From 4420b223a2b101f6935e71503dd5b4dabf0bc7f6 Mon Sep 17 00:00:00 2001 From: Dominik Baran Date: Fri, 31 May 2024 17:35:45 +0200 Subject: [PATCH] fix: soap action parsing for malformed data --- src/SoapCore.Tests/InvalidXMLTests.cs | 65 ++++++++++++++++++++++++++ src/SoapCore/HeadersHelper.cs | 6 +++ src/SoapCore/SoapEndpointMiddleware.cs | 16 ++++--- 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/SoapCore.Tests/InvalidXMLTests.cs b/src/SoapCore.Tests/InvalidXMLTests.cs index 8dfdd0d6..ac261b4c 100644 --- a/src/SoapCore.Tests/InvalidXMLTests.cs +++ b/src/SoapCore.Tests/InvalidXMLTests.cs @@ -126,6 +126,71 @@ public async Task DuplicatedElement() Assert.IsTrue(body.Contains("a c")); } + [DataTestMethod] + [DataRow("application/soap+xml; charset=utf-8; action=\"Request\"")] + [DataRow("application/soap+xml; charset=utf-8; action=\"Request/\"")] + [DataRow("application/soap+xml; charset=utf-8; action=\"testRequest/\"")] + [DataRow("application/soap+xml; charset=utf-8; action=\"TESTRequest/\"")] + [DataRow("application/soap+xml; charset=utf-8; action=\"/\"")] + [DataRow("application/soap+xml; charset=utf-8; action=\"https://dos.brianfeucht.com/test/\"")] + [DataRow("application/soap+xml; charset=utf-8; action=\"https://dos.brianfeucht.com/test\"")] + [DataRow("application/soap+xml; charset=utf-8; action=\"https://dos.brianfeucht.com/TEST\"")] + [DataRow("application/soap+xml; charset=utf-8; action=\"https://dos.brianfeucht.com/Test\"")] + public async Task InvalidSoapActionContentType(string contentType) + { + // Arrange + var logger = NullLoggerFactory.Instance.CreateLogger>(); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSingleton(); + serviceCollection.AddSoapCore(); + + var options = new SoapOptions() + { + Path = "/Service.asmx", + EncoderOptions = new[] + { + new SoapEncoderOptions + { + MessageVersion = MessageVersion.Soap12WSAddressing10, + WriteEncoding = Encoding.UTF8, + ReaderQuotas = XmlDictionaryReaderQuotas.Max + } + }, + ServiceType = typeof(DuplicatedElementService), + SoapModelBounder = new MockModelBounder(), + SoapSerializer = SoapSerializer.XmlSerializer + }; + + var soapCore = new SoapEndpointMiddleware(logger, _ => Task.CompletedTask, options); + + var context = new DefaultHttpContext(); + context.Request.Path = new PathString("/Service.asmx"); + context.Request.Method = "POST"; + context.Response.Body = new MemoryStream(); + + // Act + var request = @" + + + + a + c + + +"; + context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(request), false); + context.Request.ContentType = contentType; + + await soapCore.Invoke(context, serviceCollection.BuildServiceProvider()); + + // Assert + context.Response.Body.Seek(0, SeekOrigin.Begin); + using var response = new StreamReader(context.Response.Body, Encoding.UTF8); + var body = await response.ReadToEndAsync(); + Assert.IsTrue(body.Contains("a c")); + } + [ServiceContract(Namespace = "https://dos.brianfeucht.com/")] public class DenialOfServiceProofOfConcept { diff --git a/src/SoapCore/HeadersHelper.cs b/src/SoapCore/HeadersHelper.cs index 27369d45..0345595a 100644 --- a/src/SoapCore/HeadersHelper.cs +++ b/src/SoapCore/HeadersHelper.cs @@ -98,6 +98,12 @@ public static string GetSoapAction(HttpContext httpContext, ref Message message) } } + if (soapAction != null && + (string.IsNullOrEmpty(GetTrimmedSoapAction(soapAction)) || string.IsNullOrEmpty(GetTrimmedClearedSoapAction(soapAction)))) + { + soapAction = string.Empty; + } + if (string.IsNullOrEmpty(soapAction)) { if (!string.IsNullOrEmpty(message.Headers.Action)) diff --git a/src/SoapCore/SoapEndpointMiddleware.cs b/src/SoapCore/SoapEndpointMiddleware.cs index bc1ccbbe..db02cdf1 100644 --- a/src/SoapCore/SoapEndpointMiddleware.cs +++ b/src/SoapCore/SoapEndpointMiddleware.cs @@ -439,7 +439,11 @@ bool TryGetRequestValue(string key, out StringValues value) context.Response.ContentType = "text/xml"; var ms = new MemoryStream(); - XmlWriter writer = XmlWriter.Create(ms, new XmlWriterSettings() { Encoding = DefaultEncodings.UTF8 }); + XmlWriter writer = XmlWriter.Create(ms, new XmlWriterSettings + { + Encoding = DefaultEncodings.UTF8, + + }); XmlDictionaryWriter dictionaryWriter = XmlDictionaryWriter.CreateDictionaryWriter(writer); bodyWriter.WriteBodyContents(dictionaryWriter); @@ -566,15 +570,15 @@ private async Task ProcessMessage(Message requestMessage, SoapMessageEn private bool TryGetOperation(string methodName, out OperationDescription operation) { - operation = _service.Operations.FirstOrDefault(o => o.SoapAction.Equals(methodName, StringComparison.Ordinal) - || o.Name.Equals(HeadersHelper.GetTrimmedSoapAction(methodName), StringComparison.Ordinal) - || methodName.Equals(HeadersHelper.GetTrimmedSoapAction(o.Name), StringComparison.Ordinal)); + operation = _service.Operations.FirstOrDefault(o => o.SoapAction.Equals(methodName, StringComparison.OrdinalIgnoreCase) + || o.Name.Equals(HeadersHelper.GetTrimmedSoapAction(methodName), StringComparison.OrdinalIgnoreCase) + || methodName.Equals(HeadersHelper.GetTrimmedSoapAction(o.Name), StringComparison.OrdinalIgnoreCase)); if (operation == null) { operation = _service.Operations.FirstOrDefault(o => - methodName.Equals(HeadersHelper.GetTrimmedClearedSoapAction(o.SoapAction), StringComparison.Ordinal) - || methodName.Contains(HeadersHelper.GetTrimmedSoapAction(o.Name))); + methodName.Equals(HeadersHelper.GetTrimmedClearedSoapAction(o.SoapAction), StringComparison.OrdinalIgnoreCase) + || methodName.IndexOf(HeadersHelper.GetTrimmedSoapAction(o.Name), StringComparison.OrdinalIgnoreCase) >= 0); } return operation != null;