Skip to content

Commit 187ef35

Browse files
authored
Merge pull request #1664 from HackTricks-wiki/update_SOAPwn__Pwning__NET_Framework_Applications_Through_20251211_184320
SOAPwn Pwning .NET Framework Applications Through HTTP Clien...
2 parents 99621ea + 43987a0 commit 187ef35

File tree

3 files changed

+111
-1
lines changed

3 files changed

+111
-1
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@
439439
- [Firebase Database](network-services-pentesting/pentesting-web/buckets/firebase-database.md)
440440
- [CGI](network-services-pentesting/pentesting-web/cgi.md)
441441
- [Django](network-services-pentesting/pentesting-web/django.md)
442+
- [Dotnet Soap Wsdl Client Exploitation](network-services-pentesting/pentesting-web/dotnet-soap-wsdl-client-exploitation.md)
442443
- [DotNetNuke (DNN)](network-services-pentesting/pentesting-web/dotnetnuke-dnn.md)
443444
- [Drupal](network-services-pentesting/pentesting-web/drupal/README.md)
444445
- [Drupal RCE](network-services-pentesting/pentesting-web/drupal/drupal-rce.md)

src/network-services-pentesting/pentesting-web/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ Some **tricks** for **finding vulnerabilities** in different well known **techno
7676
- [**Artifactory**](artifactory-hacking-guide.md)
7777
- [**Buckets**](buckets/index.html)
7878
- [**CGI**](cgi.md)
79+
- [**Dotnet SOAP WSDL client exploitation**](dotnet-soap-wsdl-client-exploitation.md)
7980
- [**Drupal**](drupal/index.html)
8081
- [**Flask**](flask.md)
8182
- [**Fortinet FortiWeb**](fortinet-fortiweb.md)
@@ -435,4 +436,4 @@ Entry_12:
435436
436437
</details>
437438
438-
{{#include ../../banners/hacktricks-training.md}}
439+
{{#include ../../banners/hacktricks-training.md}}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# .NET SOAP/WSDL Client Proxy Abuse
2+
3+
{{#include ../../banners/hacktricks-training.md}}
4+
5+
## TL;DR
6+
7+
- `SoapHttpClientProtocol`, `DiscoveryClientProtocol` and friends inherit from `HttpWebClientProtocol`, whose `GetWebRequest()` returns the scheme-agnostic `WebRequest` instance produced by `WebRequest.Create()` without enforcing `HttpWebRequest`.
8+
- 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.
9+
- 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.
10+
11+
## Root cause: HttpWebClientProtocol is scheme-agnostic
12+
13+
`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`:
14+
15+
- `http(s)://``HttpWebRequest`
16+
- `file:///` or `\\host\share\``FileWebRequest`
17+
- `ftp://``FtpWebRequest`
18+
19+
`SoapHttpClientProtocol.Invoke()` then streams the SOAP POST body through whatever transport handler was selected, even if that means writing to disk or over SMB.
20+
21+
## Primitive 1 – NTLM capture / relay via UNC targets
22+
23+
1. Gain control over `SoapHttpClientProtocol.Url` (direct setter, config value, database row, etc.).
24+
2. Point it to a UNC path like `file://attacker.local/sink/payload`.
25+
3. The CLR opens the path via SMB and performs integrated authentication, leaking NTLM challenge/response to the attacker.
26+
4. Use captured hashes for offline cracking or NTLM relay (SMB/HTTP) if signing/EPA are absent.
27+
28+
This applies to **any** .NET SOAP/HTTP proxy path that accepts user input, even if no further exploitation is possible.
29+
30+
## Primitive 2 – Arbitrary file writes via `file://`
31+
32+
1. Set `Url = "file:///inetpub/wwwroot/poc.aspx"` (or any writable path) before the proxy call.
33+
2. Invoke any SOAP method; the framework writes the entire SOAP envelope to the chosen path, overwriting existing files.
34+
3. User-controlled arguments appear inside XML elements, letting attackers drop CSHTML/ASPX payloads or poison config files.
35+
36+
Limitations:
37+
38+
- Content is always XML; scalar fields are entity-encoded, so injecting `<script>` via plain strings requires additional tricks.
39+
- Meaningful payloads need at least one attacker-influenced argument or the ability to modify the method signature (see WSDL abuse).
40+
41+
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.
42+
43+
## Weaponizing WSDL imports
44+
45+
### Auto-generated proxies via `ServiceDescriptionImporter`
46+
47+
Many products expose "custom web service" features that accept a WSDL URL, then:
48+
49+
1. `ServiceDescription.Read()` the attacker-controlled WSDL.
50+
2. `ServiceDescriptionImporter` generates C# proxy classes extending `SoapHttpClientProtocol`.
51+
3. CodeDOM compiles the proxy and reflection calls the requested method.
52+
53+
The attacker fully controls:
54+
55+
- `soap:address` / `soap12:address` `location` → becomes `base.Url` (can set `file://` or UNC paths).
56+
- Method names, parameter lists, complex types and serializers.
57+
- Namespace URIs that end up as `xmlns:*` attributes in every SOAP message.
58+
59+
No scheme validation occurs, so every generated proxy inherits the original design flaw.
60+
61+
### Shaping the SOAP envelope for RCE
62+
63+
- **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:
64+
```xml
65+
<script runat="server">
66+
// payload pulling `Request.QueryString["cmd"]`
67+
</script>
68+
```
69+
and point `Url` to `file:///.../webroot/shell.aspx` to gain RCE.
70+
- **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.
71+
72+
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.
73+
74+
## Typical attack workflow
75+
76+
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`).
77+
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.
78+
3. Trigger the import/compilation. The target emits a proxy DLL with attacker-controlled constructor and methods.
79+
4. When the application invokes the generated method, the SOAP request is serialized and written to the attacker-specified path, embedding the payload.
80+
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.
81+
82+
## Detection & hunting
83+
84+
- **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.
85+
- **Runtime telemetry**:
86+
- Instrument proxy creation to log schemes; alert on `file`, `ftp`, or UNC values.
87+
- Monitor for the characteristic "Client found response content type of 'application/octet-stream'" errors after SOAP calls.
88+
- Watch for unexpected `.aspx/.cshtml/.ps1` writes under application directories performed by the web service identity.
89+
- **Network/file signals**: SMB connections initiated by web servers to attacker infrastructure, or sudden compilation of temporary proxy DLLs, often precede exploitation.
90+
91+
## Mitigations
92+
93+
- **Enforce transport validation** before invoking any `HttpWebClientProtocol`-derived proxy:
94+
```csharp
95+
var uri = new Uri(proxy.Url);
96+
if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)
97+
throw new InvalidOperationException("SOAP clients must stay on HTTP/S");
98+
```
99+
- **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.
100+
- **Disable untrusted WSDL features**: Replace "upload a WSDL" conveniences with vetted, server-side templates or allowlists.
101+
- **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.
102+
- **Harden NTLM exposure**: Disable outbound SMB where possible; otherwise enforce SMB signing, EPA and other relay mitigations.
103+
104+
## References
105+
106+
- [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/)
107+
108+
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)