Showing posts with label Port scanning. Show all posts
Showing posts with label Port scanning. Show all posts

22/02/2020

SSRFing External Service Interaction and Out of Band Resource Load (Hacker's Edition)

External Service Interaction & Out-of-Band Resource Loads — Updated 2026

External Service Interaction & Out-of-Band Resource Loads

Host Header Exploitation // SSRF Primitives // Infrastructure Pivoting
SSRF Host Header Injection CWE-918 OWASP A10:2021 Cache Poisoning Updated 2026

In the recent past we encountered two relatively new types of attacks: External Service Interaction (ESI) and Out-of-Band Resource Loads (OfBRL).

  1. An ESI [1] occurs only when a web application allows interaction with an arbitrary external service.
  2. OfBRL [6] arises when it is possible to induce an application to fetch content from an arbitrary external location, and incorporate that content into the application's own response(s).
Taxonomy Note (2026): Both ESI and OfBRL are now classified under OWASP A10:2021 — SSRF and map to CWE-918 (Server-Side Request Forgery). ESI also maps to CWE-441 (Unintentional Proxy or Intermediary).

The Problem with OfBRL

The ability to request and retrieve web content from other systems can allow the application server to be used as a two-way attack proxy (when OfBRL is applicable) or a one-way proxy (when ESI is applicable). By submitting suitable payloads, an attacker can cause the application server to attack, or retrieve content from, other systems that it can interact with. This may include public third-party systems, internal systems within the same organization, or services available on the local loopback adapter of the application server itself. Depending on the network architecture, this may expose highly vulnerable internal services that are not otherwise accessible to external attackers.

The Problem with ESI

External service interaction arises when it is possible to induce an application to interact with an arbitrary external service, such as a web or mail server. The ability to trigger arbitrary external service interactions does not constitute a vulnerability in its own right, and in some cases might even be the intended behavior of the application. However, in many cases, it can indicate a vulnerability with serious consequences.

Attacker Host: malicious.com Vulnerable application Trusts Host header blindly ESI path OfBRL path External service DNS / HTTP interaction External resource Content fetched + returned One-way proxy No content returned Two-way proxy Content in app response CWE-918 / CWE-441 CWE-918 / A10:2021
Figure 1 — ESI (one-way) vs OfBRL (two-way) attack paths

The Verification

We do not have ESI or OfBRL when:

  1. In Collaborator, the source IP is our browser IP (the server didn't make the request).
  2. There is a 302 redirect from our host to the Collaborator (i.e. our source IP appears in the Collaborator logs, not the server's).

Below we can see the original configuration in the repeater, followed by the modified configuration for the test. In the original request, the Host header reflects the legitimate domain. In the test request, we replace it with our Collaborator payload or target host.

Original request

GET / HTTP/1.1 Host: our_vulnerableapp.com Pragma: no-cache Cache-Control: no-cache, no-transform Connection: close

Malicious requests

GET / HTTP/1.1 Host: malicious.com Pragma: no-cache Cache-Control: no-cache, no-transform Connection: close
GET / HTTP/1.1 Host: 127.0.0.1:8080 Pragma: no-cache Cache-Control: no-cache, no-transform Connection: close

If the application is vulnerable to OfBRL, the reply is going to be processed by the vulnerable application, bounce back to the sender (the attacker) and potentially load in the context of the application. If the reply does not come back to the sender, then we might have an ESI, and further investigation is required.

The RFCs Updated

It usually is a platform issue and not an application one. In some scenarios when we have, for example, a CGI application, the HTTP headers are handled by the application (i.e. the app is dynamically manipulating the HTTP headers to run properly). This means that HTTP headers such as Location and Host are handled by the app and therefore a vulnerability might exist. It is recommended to run HTTP header integrity checks when you own a critical application that is running on your behalf.

For more information on the subject, read RFC 9110 (HTTP Semantics, June 2022) [2] and RFC 9112 (HTTP/1.1 Message Syntax and Routing) [2b], which supersede the obsolete RFC 2616. The Host request-header field specifies the Internet host and port number of the resource being requested, as obtained from the original URI. The Host field value MUST represent the naming authority of the origin server or gateway given by the original URL. This allows the origin server or gateway to differentiate between internally-ambiguous URLs, such as the root "/" URL of a server for multiple host names on a single IP address.

RFC Update: RFC 2616 was obsoleted in 2014 by RFCs 7230–7235, which were themselves superseded by RFCs 9110–9112 in June 2022. All references in this article now point to the current standards.

When TLS is enforced throughout the whole application (even the root path /), an ESI or OfBRL is significantly harder to exploit, because TLS performs source origin authentication — as soon as a connection is established with an IP, the protocol guarantees that the connection will serve traffic only from the original certificate holder. More specifically, we are going to get an SNI error.

SNI prevents what's known as a "common name mismatch error": when a client device reaches the IP address of a vulnerable app, but the name on the TLS certificate doesn't match the name of the website. SNI was added to the IETF's Internet RFCs in June 2003 through RFC 3546, with the latest version in RFC 6066. The current TLS 1.3 specification is RFC 8446 [10].

ECH Warning (2025+): Encrypted Client Hello (ECH), specified in RFC 8744 and actively being deployed by major browsers and CDNs, encrypts the SNI field within the TLS handshake. This means that SNI-based filtering and inspection at network perimeters becomes ineffective when ECH is in use. Security teams should account for this when relying on SNI as a defensive control.
Attacker Host: evil.com TLS ClientHello SNI: evil.com TLS termination Cert: vulnapp.com SNI mismatch check evil.com ≠ vulnapp.com Connection refused (SNI error) Note: ECH (RFC 8744) encrypts SNI — changes this model
Figure 2 — TLS/SNI protection mechanism (and its ECH caveat)

The option to trigger an arbitrary external service interaction does not constitute a vulnerability in its own right, and in some cases it might be the intended behavior of the application. But we as hackers want to exploit it — what can we do with an ESI or an Out-of-Band Resource Load?

The Infrastructure

Well, it depends on the overall setup. The highest-value scenarios are the following:

  1. The application is behind a WAF (with restrictive ACLs)
  2. The application is behind a UTM (with restrictive ACLs)
  3. The application is running multiple applications in a virtual environment
  4. The application is running behind a NAT
  5. The application runs in a cloud environment with metadata endpoints accessible from localhost
  6. The application runs in a containerized environment (Docker/Kubernetes) with internal service discovery

In order to perform the attack, we simply inject our host value in the HTTP Host header (hostname including port).

Attacker Host: 127.0.0.1:8080 WAF / UTM / load balancer Passes request (Host trusted) DMZ / internal network Vulnerable app server Processes injected Host localhost 127.0.0.1:* Admin panels Internal mgmt UIs DMZ hosts 192.168.x.x Cloud metadata 169.254.169.254 Container services K8s API / sidecars Trusted IP = app server IP → bypasses ACLs, firewalls, network segmentation
Figure 3 — Host header injection pivoting through infrastructure (including cloud/container targets)

The Test

Burp Professional edition has a feature named Collaborator. Burp Collaborator is a network service that Burp Suite uses to help discover vulnerabilities such as ESI and OfBRL [3]. A typical example would be to use Burp Collaborator to test if ESI exists.

Burp Collaborator request

GET / HTTP/1.1 Host: edgfsdg2zjqjx5dwcbnngxm62pwykabg24r.burpcollaborator.net Pragma: no-cache Cache-Control: no-cache, no-transform Connection: keep-alive

Burp Collaborator response

HTTP/1.1 200 OK Server: Burp Collaborator https://burpcollaborator.net/ X-Collaborator-Version: 4 Content-Type: text/html Content-Length: 53 <html><body>drjsze8jr734dsxgsdfl2y18bm1g4zjjgz</body></html>

The Post Exploitation

As hacker-artists, we now think about how to exploit this. The scenarios are: [7] [8]

  1. Attempt to load the local admin panels.
  2. Attempt to load the admin panels of surrounding applications.
  3. Attempt to interact with other services in the DMZ.
  4. Attempt to port scan localhost.
  5. Attempt to port scan DMZ hosts.
  6. Use it to exploit IP trust and run a DoS attack against other systems.
  7. Access cloud metadata endpoints to extract IAM credentials or instance identity tokens.
  8. Probe Kubernetes API or container sidecar services (e.g. Envoy admin on localhost:15000).

A good tool for automating this is Burp Intruder [4]. Using Sniper mode, we can:

  1. Rotate through different ports, using the vulnapp.com domain name.
  2. Rotate through different ports, using the vulnapp.com external IP.
  3. Rotate through different ports, using the vulnapp.com internal IP, if applicable.
  4. Rotate through different internal IPs in the same domain, if applicable.
  5. Rotate through different protocols (may not always work).
  6. Brute-force directories on identified DMZ hosts.

Burp Intruder — scanning surrounding hosts

GET / HTTP/1.1 Host: 192.168.1.§§ Pragma: no-cache Cache-Control: no-cache, no-transform Connection: close

Burp Intruder — port scanning surrounding hosts

GET / HTTP/1.1 Host: 192.168.1.1:§§ Pragma: no-cache Cache-Control: no-cache, no-transform Connection: close

Burp Intruder — port scanning localhost

GET / HTTP/1.1 Host: 127.0.0.1:§§ Pragma: no-cache Cache-Control: no-cache, no-transform Connection: close

Modern Attack Vectors New 2026

Since the original publication of this article, several high-impact attack surfaces have emerged that directly exploit ESI/OfBRL primitives:

Cloud metadata endpoint exploitation

Cloud providers expose instance metadata via link-local addresses. When a vulnerable application can be coerced into making requests to these endpoints via Host header injection, an attacker can extract IAM credentials, service account tokens, instance identity documents, and network configuration details.

GET / HTTP/1.1 Host: 169.254.169.254 # AWS IMDSv1 — returns IAM role credentials GET / HTTP/1.1 Host: metadata.google.internal # GCP — returns service account tokens GET / HTTP/1.1 Host: 169.254.169.254 Metadata: true # Azure — requires Metadata header (may not work via Host injection alone)
Mitigation: AWS IMDSv2 mitigates this by requiring a PUT request with a TTL-bounded token (hop limit = 1). GCP Compute VMs support a similar metadata concealment mechanism. Ensure your cloud instances enforce these protections.

Container and Kubernetes exploitation

In containerized environments, the application server often has network access to internal Kubernetes services that are never meant to be internet-facing:

GET / HTTP/1.1 Host: kubernetes.default.svc:443 # K8s API server — may leak secrets, pod specs, RBAC config GET / HTTP/1.1 Host: 127.0.0.1:15000 # Envoy sidecar admin — config dump, cluster endpoints, stats GET / HTTP/1.1 Host: 127.0.0.1:9090 # Prometheus metrics — may expose internal service topology

Practical cache poisoning (Kettle, 2018)

James Kettle's 2018 PortSwigger research on practical web cache poisoning significantly expanded the attack surface understanding for Host header injection. His work demonstrated that unkeyed HTTP headers (including Host, X-Forwarded-Host, and X-Forwarded-Scheme) can be used to poison shared caches (CDNs, reverse proxies) at scale, affecting all users served by the poisoned cache entry. This research formalized the technique that was previously theoretical into a repeatable, high-impact attack chain.

Step 1: Attacker poisons Attacker Host: evil.com Vulnerable app Response Links rewritten to evil.com Step 2: Cache stores poisoned response Shared cache / CDN / proxy Cached: / → poisoned response Step 3: Legitimate users get poisoned content User A User B User C All users served poisoned content Until cache TTL expires or entry is manually purged
Figure 4 — Cache poisoning via Host header injection

What Can You Do

The full exploitation analysis — this vulnerability can be used in the following ways:

  1. Bypass restrictive UTM ACLs
  2. Bypass restrictive WAF rules
  3. Bypass restrictive firewall ACLs
  4. Perform cache poisoning
  5. Fingerprint internal infrastructure
  6. Perform DoS exploiting IP trust
  7. Exploit applications hosted on the same machine (multiple app loads)
  8. Extract cloud IAM credentials via metadata endpoints
  9. Map Kubernetes cluster topology via internal service discovery
  10. Exfiltrate data through DNS-based out-of-band channels

The impact of a maliciously constructed response can be magnified if it is cached either by a shared web cache or the browser cache of a single user. If a response is cached in a shared web cache, such as those commonly found in proxy servers or CDNs, then all users of that cache will continue to receive the malicious content until the cache entry is purged. Similarly, if the response is cached in the browser of an individual user, that user will continue to receive the malicious content until the cache entry expires [5].

What Can't You Do

You cannot perform XSS or CSRF exploiting this vulnerability, unless certain conditions apply (e.g. the poisoned response injects attacker-controlled JavaScript into a cached page, or the application reflects the Host header value into HTML output without encoding).

The Fix Updated

If the ability to trigger arbitrary ESI or OfBRL is not intended behavior, then you should implement a whitelist of permitted URLs, and block requests to URLs that do not appear on this whitelist [6]. Running host integrity checks is also recommended.

Review the purpose and intended use of the relevant application functionality, and determine whether the ability to trigger arbitrary external service interactions is intended behavior. If so, be aware of the types of attacks that can be performed via this behavior and take appropriate measures. These measures might include blocking network access from the application server to other internal systems, and hardening the application server itself to remove any services available on the local loopback adapter.

More specifically, we can:

  1. Apply egress filtering on the DMZ
  2. Apply egress filtering on the host (iptables/nftables rules, or cloud security group outbound rules)
  3. Apply whitelist IP restrictions in the application
  4. Apply blacklist restrictions in the application (not recommended — incomplete by nature)
  5. Validate and normalize the Host header at the reverse proxy layer before it reaches the application (e.g. Nginx server_name directive with explicit hostnames, reject requests with unknown Host values)
  6. Use X-Forwarded-Host with strict allowlisting rather than trusting the raw Host header — and ensure the reverse proxy strips any client-supplied X-Forwarded-* headers before adding its own
  7. Enforce IMDSv2 on cloud instances (hop limit = 1, PUT-based token acquisition) to block Host header SSRF to metadata endpoints
  8. Apply Kubernetes NetworkPolicies to restrict pod-to-pod and pod-to-service communication to only what's necessary
  9. Deploy egress proxies for any application that legitimately needs to make outbound HTTP requests — force all outbound traffic through a proxy with domain allowlisting

21/03/2012

Quick Reference on Port Scanning

Intro

This article is about basic types of port scanning.

Port States (taking from Nmap man page)

open

An application is actively accepting TCP connections, UDP datagrams or SCTP associations on this port.

closed

A closed port is accessible (it receives and responds to Nmap probe packets), but there is no application listening on it. They can be helpful in showing that a host is up on an IP address (host discovery, or ping scanning), and as part of OS detection. Because closed ports are reachable, it may be worth scanning later in case some open up. Administrators may want to consider blocking such ports with a firewall. Then they would appear in the filtered state, discussed next.

filtered

Nmap cannot determine whether the port is open because packet filtering prevents its probes from reaching the port. The filtering could be from a dedicated firewall device, router rules, or host-based firewall software. Sometimes they respond with ICMP error messages such as type 3 code 13 (destination unreachable: communication administratively prohibited), but filters that simply drop probes without responding are far more common.

unfiltered

The unfiltered state means that a port is accessible, but Nmap is unable to determine whether it is open or closed. Only the ACK scan, which is used to map firewall rulesets, classifies ports into this state. Scanning unfiltered ports with other scan types such as Window scan, SYN scan, or FIN scan, may help resolve whether the port is open.

open|filtered

Nmap places ports in this state when it is unable to determine whether a port is open or filtered. This occurs for scan types in which open ports give no response. The lack of response could also mean that a packet filter dropped the probe or any response it elicited. So Nmap does not know for sure whether the port is open or being filtered. The UDP, IP protocol, FIN, NULL, and Xmas scans classify ports this way.

closed|filtered

This state is used when Nmap is unable to determine whether a port is closed or filtered. It is only used for the IP ID idle scan.

TCP SYN scan (with Hping2)

Scanner --- SYN (Sequence Number Set to 1) ---> Target
Scanner <- SYN/ACK (Sequence Number Set 0 and Acknowledgment Set 0) - Target
Scanner --- RST (Sequence Number Set Again to 1) ---> Target (Only if host listens)

Note: Scanner Viciously Dropped The Connection.

Or

Scanner --- RST/ACK ---> Target (Not used by Hping2 connection termination pattern)

Note: Graciously Terminated connection? (both parties have ti exchange an ACK flag), see below.

Scanner --- FIN ---> Target
Scanner <--- FIN/ACK --- Target
Scanner --- ACK ---> Target

Only a SYN packet is sent to the target port.If a SYN/ACK is received from the target port, we can deduce that it is in the LISTENING state. If a RST/ACK is received, it usually indicates that the port is not listening, but we can deduce that the host is up. A RST/ACK or RST can be sent by the system performing the port scan so that a full connection is never established (also known as half open connections).

Half Open Connections in SYN scans

A connection can be "half-open", in which case one side has terminated its end, but the other has not. The side that has terminated can no longer send any data into the connection, but the other side can. The terminating side should continue reading the data until the other side terminates as well (always based in RFC's).

Connection termination in port scanning?

The connection termination phase uses, at most, a four-way handshake, with each side of the connection terminating independently. When an endpoint wishes to stop its half of the connection, it transmits a FIN packet, which the other end acknowledges with an ACK. Therefore, a typical tear-down requires a pair of FIN and ACK segments from each TCP endpoint. After both FIN/ACK exchanges are concluded, the terminating side waits for a timeout before finally closing the connection, during which time the local port is unavailable for new connections; this prevents confusion due to delayed packets being delivered during subsequent connections.It is also possible to terminate the connection by a 3-way handshake, when host A sends a FIN and host B replies with a FIN & ACK (merely combines 2 steps into one) and host A replies with an ACK. This is perhaps the most common method.

TCP ACK scan (with Hping2)

Scanner - ACK (Sequence Number Set 0 and Acknowledgment Set 0)-> Target
Scanner <--- RST (Sequence Number Set Again to 1) ---> Target

Or

Scanner <--- Connection Timeout or Sent ICMP Error --- Target

The ACK scan probe packet has only the ACK flag set (unless you use --scanflags with Nmap). When scanning unfiltered systems, open and closed ports will both return a RST packet. Nmap then labels them as unfiltered, meaning that they are reachable by the ACK packet, but whether they are open or closed is undetermined. Ports that don't respond, or send certain ICMP error messages back (type 3, code 1, 2, 3, 9, 10, or 13), are ussually labeled filtered by Nmap.

TCP Full Handshake or Connect scan (with Hping2)

Scanner --- SYN (Sequence Number Set to 0) ---> Target
Scanner <--- SYN/ACK (Sequence Number Set 0 and Acknowledgment Set 1) --- Target
Scanner --- ACK (Sequence Number Set 1 and Acknowledgment Set 1) ---> Target
Scanner --- FIN/ACK ---> Target
Scanner <--- ACK --- Target

Or

Scanner --- RST ---> Target (Nmap terminates the connection this way!)

Note: This type of scans might be logged from firewalls based always type and configuration of firewalls.

UDP scan (with Hping2)

Scanner --- UDP ---> Target
Scanner <--- ICMP error (for closed ports) --- Target
Scanner <--- Connection Timeout (for open or filtered ports) --- Target

When a UDP packet is sent to a port that is not open, the system will respond with an ICMP port unreachable message. Most UDP port scanners use this scanning method, and use the absence of a response to infer that a port is open. However, if a port is blocked by a firewall, this method will falsely report that the port is open.

TCP NULL scan (with Hping2)

Scanner --- NULL ---> Target (All flags is set to 0)
Scanner <--- RST --- Target

Or

Scanner <--- Timeout Connection --- Target (Target host is filtered from firewall that silently drops the
connection)

TCP Null scan This technique turns off all fl ags. Based on RFC 793, the target system should send back an RST for all closed ports.

TCP FIN scan (with Hping2)

Scanner --- FIN ---> Target
Scanner <--- RST --- Target

Or

Scanner <--- Timeout Connection --- Target (Target host is filtered from firewall that silently drops the
connection)

TCP FIN scan This technique sends a FIN packet to the target port. Based on RFC 793 (http://ww.ietf.org/rfc/rfc0793.txt), the target system should send back an RST for all closed ports. This technique usually only works or used to worj on UNIXbased TCP/IP stacks.

TCP Xmas scan (with Hping2)

Scanner --- FIN,URG,PUSH ---> Target
Scanner <--- RST --- Target (For all closed ports, drop connection; works in UNIXboxs)

Or

Scanner <--- Timeout Connection --- Target (Target host is filtered and silently drops the connection)

TCP Xmas Tree scan This technique sends a FIN, URG, and PUSH packet to the target port. Based on RFC 793, the target system should send back an RST for all closed ports.

TCP Window scan (with Hping2)

Scanner - ACK (Sequence Number Set 0 and Acknowledgment Set 0)-> Target
Scanner <--- RST (Sequence Number Set Again to 1) ---> Target


Or

Scanner <--- Connection Timeout or Sent ICMP Error --- Target


Window scan is exactly the same as ACK scan except that it exploits an implementation detail of certain systems to differentiate open ports from closed ones, rather than always printing unfiltered when a RST is returned. It does this by examining the TCP Window field of the RST packets returned. On some systems, open ports use a positive window size (even for RST packets) while closed ones have a zero window. So instead of always listing a port as unfiltered when it receives a RST back, Window scan lists the port as open or closed if the TCP Window value in that reset is positive or zero, respectively.

TCP Mainmon scan (with Hping2 used for BSD hosts)

Scanner --- FIN/ACK ---> Target
Scanner <--- RST (Possibly) --- Target

Or

Scanner <--- Timeout Connection --- Target (Target host is filtered and silently drops the connection)

The Maimon scan is named after its discoverer, Uriel Maimon. He described the technique in Phrack Magazine issue #49 (November 1996). Nmap, which included this technique, was released two issues later. This technique is exactly the same as NULL, FIN, and Xmas scans, except that the probe is FIN/ACK. According to RFC 793 (TCP), a RST packet should be generated in response to such a probe whether the port is open or closed. However, Uriel noticed that many BSD-derived systems simply drop the packet if the port is open.

TCP Idle Scan (using Nmap)

Scanner --- SYN/ACK ---> Zombie
Scanner <--- RST with IP ID = 1 --- Zombie
Scanner --- Forged from zombie SYN ---> Target

Then when open port:

Target --- SYN/ACK ---> Zombie
Target <--- RST IP ID = 2 --- Zombie
Scanner --- SYN/ACK ---> Zombie
Scanner <--- RST IP ID = 3 --- Zombie 

Or when closed or filtered port:

Target --- Timeout  or RST ---> Zombie (With timeout or RST no ID is increased)
Scanner --- SYN/ACK ---> Zombie
Scanner <--- RST IP ID = 2 --- Zombie

Fundamentally, an idle scan consists of three steps that are repeated for each port:
  1. Probe the zombie's IP ID and record it.
  2. Forge a SYN packet from the zombie and send it to the desired port on the target. Depending on the port state, the target's reaction may or may not cause the zombie's IP ID to be incremented.
  3. Probe the zombie's IP ID again. The target port state is then determined by comparing this new IP ID with the one recorded in step 1.
References:

http://www.pcvr.nl/tcpip/udp_user.htm
http://www.techrepublic.com/article/exploring-the-anatomy-of-a-data-packet/1041907
http://www.freesoft.org/CIE/Course/Section3/7.htm

CVE-2025-59536: When Your Coding Agent Becomes the Backdoor

// ELUSIVE THOUGHTS — APPSEC / AI AGENTS CVE-2025-59536: When Your Coding Agent Becomes the Backdoor Posted by Jerry — May 2026 On F...