the_open_door
coffee
ESEN
← Back to index

Internal port discovery via Squid

Squid is a caching HTTP proxy. When it is exposed without an access-control list (a misconfigured http_access directive), an attacker can use it as a pivot: the requests we send get forwarded by the proxy, so they reach the destination from the proxy machine itself. That makes it possible to reach services that only listen on localhost or on internal interfaces which look filtered from outside.

The immediate consequence is a port sweep through the proxy. Pointing curl at the proxy port (3128 by default) and repeatedly asking it for the same host on different ports, the response code reveals which internal ports are alive:

curl -s -I --connect-timeout 2 -x http://<ip>:3128 http://<ip>:<port>

An HTTP/1.1 200 (or any service response) means the port answers internally; a connection failure means it is closed or filtered. Automating it with a loop over all 65535 ports reveals the whole internal surface in minutes:

for p in $(seq 1 65535); do
  code=$(curl -s -I --connect-timeout 2 -x http://<ip>:3128 "http://<ip>:$p" | head -1 | cut -d' ' -f2)
  [ "$code" = "200" ] && echo "[+] $p open"
done

Why it happens. The proxy is meant to forward traffic from trusted clients, but without an ACL it forwards anyone's. The difference from a direct nmap scan is the point of view: nmap sees what is exposed externally; the proxy sees what the machine sees of itself, and that usually includes admin panels meant to be local (a phpMyAdmin, a WAMP panel on 8080, a database on 3306).

Caveat. Not every service speaks HTTP, so a 200 is only reliable for web ports; other ports may be open yet not return 200. Treat the result as a hint (a port that accepts a connection) and confirm by pointing the browser through the proxy. From there, a RCE or a webshell on one of those internal services is the logical next step.

How to detect it. The signature is in Squid's access.log: a single client requesting the same host on hundreds of different ports in a short time, with many TCP_MISS/TCP_DENIED lines and requests to internal IPs or localhost, a port-sweep pattern that legitimate proxy use never generates. A rule counting distinct destinations/ports per client, or alerting on proxy requests toward internal ranges, detects it. A CONNECT to non-web ports (3306, 6379) through the proxy is especially telling.

Defence. Restrict http_access to trusted networks, do not expose Squid to the Internet, and segment so the proxy cannot reach sensitive services that should stay isolated.

Machines where it's used

  • SquidProving Grounds Practice