For the complete documentation index, see llms.txt. This page is also available as Markdown.
APILINUXSSRFSSTISQLIWEB

Aster Check

Lab (Master) - by Leighlin Gunner Ramsay

The following post by 0xb0b is licensed under CC BY 4.0


Scenario

AsterCheck is a vendor-risk and compliance SaaS used by security teams to track third-party attestations and automate periodic re-checks. After a contentious incident review, the company suspects their customer-facing portal is exposing more than it should and that internal tooling may be reachable in ways it wasn't designed for. You've been brought in as an external operator to validate the real-world impact, document what an attacker could obtain, and provide evidence the team can act on--without disrupting production workloads.

Summary

Summary

In AsterCheck, we begin with external enumeration and discover a single web server on port 80 redirecting to app.astercheck.local, then uncover the email, docs, and fetch virtual hosts via VHost enumeration through FFuF. The app host exposes a v2 URL preview gateway with a policy filter blocking internal hostnames, but URL-encoding the dots bypasses the filter and lets us enumerate further internal VHosts, revealing status.astercheck.local. On fetch.astercheck.local we identify a sign-then-fetch API in two versions, and by scripting the sign → fetch flow against a subdomain wordlist we discover the internal-only reports.astercheck.local VHosts. The v1 fetch endpoint accepts JSON with method, body, and headers fields, effectively turning the gateway into a full SSRF proxy that lets us replay arbitrary requests against internal hosts.

Against the reports login we attempt a basic SQL injection sweep, hit a redirect with ' or '1'='1, capture the session cookie, and reach the authenticated /dashboard and /generator endpoint as opsadmin. The report fields are rendered through a Jinja-style template engine with a denylist that blocks several payloads like {{7*7}} or {{ env }}, but the case-sensitive filter misses {{ ENV }}, leaking environment variables that disclose another internal VHost canary-code.astercheck.local. Pivoting through the fetch API one more time, we browse the internal code host, locate the fetch-gateway repository, and pull commit a1f3c9e whose message references a hardcoded signing key. The final flag sits in that commit, completing the scenario.

Recon

We use rustscan -b 500 -a 10.100.89.14 --top -- -sC -sV -Pn to enumerate all TCP ports on the target machine, piping the discovered results into Nmap which runs default NSE scripts -sC, service and version detection -sV, and treats the host as online without ICMP echo -Pn.

A batch size of 500 trades speed for stability, the default 1500 balances both, while much larger sizes increase throughput but risk missed responses and instability.

We identify a web server running on port 80. This redirects to http://app.astercheck.local/.

We add the following entry to our /etc/hosts file.

External VHOST enumeration

We try to enumerate additional virtual hosts using FFuF and find email, docs and fetch.

We edit our entry in the /etc/hosts file as follows.

Internal VHOST enumeration via SSRF URL Preview

For now, we'll stay on the app.astercheck.local virtual host page. This offers a feature o preview public URLs safely via the v2 gateway. We can already glean some information from the page. For one thing, there appears to be an earlier version since this is build v2.

For another if a preview failes the support might request a signed fetch link:

Tip: If a preview fails, support might request a “signed fetch link” for diagnostics.

We are now trying to enumerate internal services via localhost, but we can only find one on port 8000... one we already know about via fetch.astercheck.local.

Although the page mentions a policy filter that blocks requests to the virtual hosts, we try it anyway and get blocked.

However, we can work around this by using URL encoding.

We then use FFuF to enumerate additional VHosts and find status.astercheck.local.

We edit our entry in the /etc/hosts file as follows.

General Endpoint Enumeration

Next, we probe all the VHosts gathered. But none seems to have something interesting...

except the fetch vhosts.

Fetch API Endpoint Enumeration

We use Feroxbuster to list the directories on the fetch vhost and find an API endpoint in two versions, each with a sign and a fetch path. This appears to confirm the support note on app.astercheck.local.

We visit each endpoint.

The fetch endpoint requires a url paramter.

After providing a url parameter it also requires the sig parameter.

Same for the v2 version.

The sign path requires a url parameter.

After providing a url to the sign path we receive a signature.

We can use the retrieved signature to fetch the url.

Internal VHOST enumeration via Fetch API

Now we craft a script to probe for other internal vhosts via the fetch API by first requesting a signature for a url and then try to fetch it.

After running the script we identify the reports vhosts that redirects to reports/login.

We do not need to update our /etc/hosts file, since the vhost is only internally available through the fetch api.

Reports Endpoint Enumeration

Next, we try to enumerate the reports enpoint using the sign and fetch API manually. We request the signature for http://reports.astercheck.local/login...

And request it through the fetch api.

Access as opsadmin on reports.astercheck.local

We catch the request using Burp Suite to see fields required in the log in form.

Next, we need to make a POST request. The first idea was to use gopher, but the scheme renders invalid.

If we switch the method to POST for the v2 fetch we get a 405 Method Not Allowed.

But the v1 version renders an internal server error.

We change the Content-Type to application/json and this time we get a message for missing method and headers.

Now things are getting interesting. We want to test how those requests are being send to the target. So we spin up a a web server that prints the request with headers and post body.

First we sign our url.

Next, we prepare a web server that prints the request with headers and post body.

We issue a POST request through the fetch API v1 to our server.

And see that this might work how we set up the parameters.

Next we try to make a log in attempt and get the response invalid credentials.

We try to bypass the log in with some simple sql injection attempts. To slightly automate it we send the request to intruder and use the following list of payloads.

We get a redirect with ' or '1'='1!

We inspect the response and save the session cookie. The redirect points to /dashboard.

We sign the url to dashboard and make a request to is using the cookie. We are able to access the dashboard now.

For the sake of readability, the signing of each URL is no longer listed in the write-up.

We can also intercept a request made and adapt it like in repeater to view the page in our browser.

From there we are able to reach out to the generator endpoint.

SSTI in /generator

We sign the url for /generator and try to access it. Here we are able to generate reports.

From the source we can derive the parameter required to generate a report.

We try to craft an example report with arbitratry values. A report is being created.

We try some simple SSTI payloads and the created by seems to be at least evalute them, but our payload {{7*7}} is being blocked.

Several other attempts were being made. It turned out that also {{ is being blocked and also {{env}}. But we get a hit with {{ ENV }}.

This reveals the environment variable and a new vhost http://canary-code.astercheck.local.

We access it through the fetch API...

... and get access to the internal repositories.

From the source we derive the path /repo/fetch-gateway.

From there we can access two commits.

The commit a1f3c9e with the commit maessageof a hardcoded signing key stands out.

We retrieve the commit and find the flag, we reach the end of the scenario.

Last updated