The URL Fetcher That Read the Metadata Endpoint

The image preview feature fetched whatever URL it was given, so an internal address returned the instance credentials, and the response was rendered back to…

Share
The URL Fetcher That Read the Metadata Endpoint. Abstract security illustration in orange and dark grey on debugly.dev

Between the preview and the account sit 6 quiet assumptions, and the incident is the story of one of them failing.

Strip the server-side request forgery down and one property makes it severe in the cloud: the server is inside the network, so the addresses the user cannot reach are the addresses the server can, and the metadata endpoint is the credential dispenser.

This was an image preview endpoint on a cloud instance, and the mechanics are the same for any feature that fetches a user-supplied URL from the server.

Why the fetch was the vulnerability

The feature was the legitimate, and the legitimate was the preview, and the preview was the fetch, and the fetch was the server's, and the server's was the network's position, and the position was the internal's reach, and the reach was the user's input, and the input was the address, and the address was the unchecked, and the unchecked was the any, and the any was the metadata.

The check was the absent, and the absent was the allowlist, and the allowlist was the fix, and the fix was the not implemented, and the not implemented was the incident, and the incident is the reason the user-supplied URL is the untrusted input, and the untrusted is the validation's requirement, and the requirement is the discipline.

The response was the returned, and the returned was the exfiltration, and the exfiltration was the rendered, and the rendered was the convenience, and the convenience was the incident's completeness, because the fetch alone is the blind and the blind is the limited, and the returned response is the read, and the read is the total.

Why the metadata endpoint is the target

The metadata is the link-local address, and the address is the instance's, and the instance's is the no authentication, and the no authentication is the network's trust, and the trust is the position, and the position is the server's, and the server's is the SSRF's gift, and the gift is the credentials, and the credentials are the role's, and the role's is the account's access.

The credentials are the temporary, and the temporary is the hour, and the hour is the enough, and the enough is the lateral movement, and the movement is the storage and the database, and the two are the data, and the data is the breach, and the breach is the incident's scope, and the scope is the reason the metadata access should be blocked at the network layer and not only at the application.

This is the same borrowed position as the open redirect that made the phishing link look legitimate, and the shared property is the one worth fixing.

What actually fixed it

Validated the URL against an allowlist of schemes and hosts. The allowlist was the https and the known hosts, and the known hosts were the preview's legitimate sources, and the sources were the fix, and the fix was the explicit, and the explicit was the discipline, because the denylist is the bypassable and the allowlist is the closed.

Resolved the host and checked the resolved address. The resolution was the DNS, and the DNS was the rebinding's vector, and the vector was the private range's check after the resolution, and the check was the fix, and the fix was the connection to the resolved IP, and the IP was the discipline, because the hostname check alone is defeated by the rebinding.

Blocked the private and link-local ranges at the network layer. The egress rule was the metadata's deny, and the deny was the second layer, and the layer was the defence in depth, and the depth was the fix, and the fix was the firewall, and the firewall was the discipline, because the application check is the one layer and the one layer fails.

Required the instance metadata service to use the hardened mode. The mode was the token-required, and the token-required was the simple GET's failure, and the failure was the fix, and the fix was the instance's configuration, and the configuration was the discipline, because the legacy mode is the unauthenticated read.

Did not return the fetched content to the requester. The proxy was the render's own, and the own was the no exfiltration, and the no exfiltration was the blind, and the blind was the limited, and the limited was the fix, and the fix was the server-side processing, and the processing was the discipline, because the returned response turns the blind SSRF into the read.

The rule

A server that fetches a user-supplied URL can be pointed at any address the server can reach, including the cloud metadata endpoint that hands out instance credentials. Allowlist the schemes and hosts, validate the resolved IP against the private ranges, block the metadata address at the network layer, require the hardened metadata mode, and never return the fetched body to the requester.

The image preview feature fetched whatever URL it was given, and a request to the link-local metadata address returned the instance's temporary credentials straight back to the caller. The lesson I keep is the property, not the incident.