You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If enable_dns_resolution is disabled, this bypasses all private-address protection.
Scenario 2: Attacker doesn't have $2
Configure webserver to respond to requests with 302 http://127.0.0.1/csrf/me/daddy
Post a link to http://$webserver_ip/
The posted link is a public IP, so Sopel will happily load it and follow the redirect to the private address.
Scenario 3: Attacker has $2, but the above is fixed
Buy a domain, e.g. haha.bad
Set the nameservers for haha.bad to an IP you control
Run a script on that IP with the following behavior:
attack = False
if attack := not attack:
return dns_record(type="A", address="1.2.3.4", ttl=0)
return dns_record(type="A", address="127.0.0.1", ttl=0)
In the checking stage, Sopel will see the address 1.2.3.4. When performing the request, 127.0.0.1 will be used without validation. (TOCTOU)
Scenario 4: Attacker has $2 and target is IPv6
Buy a domain, e.g. haha.bad
Point haha.bad to the target IPv6 address
Post a link to http://haha.bad/csrf/me/daddy
dns.resolver.resolve() does not request AAAA records, so any combination of DNS and IPv6 passes validation.
Expected behavior
As explained on IRC, this behavior (especially the first two parts) is objectively broken and gives a false sense of security. We should either remove those config options and not pretend, or we should make url.py unable to talk to private IPs.
Environment
Sopel .version: Since before the name "Sopel" to present.
Relevant plugins: url.py
Notes
Ping @dgw and @Exirel, who requested this be an issue instead of IRC comments and a PR.
The text was updated successfully, but these errors were encountered:
Description
The url.enable_private_resolution and url.enable_dns_resolution settings do not work as advertised, and the concept of the latter is fatally flawed.
The current
url.py
private-address protection logic is as follows:This has many problems, as demonstrated below.
Reproduction steps
Oh lordy.
Scenario 1: Attacker has $2
haha.bad
haha.bad A 127.0.0.1
http://haha.bad/csrf/me/daddy
If enable_dns_resolution is disabled, this bypasses all private-address protection.
Scenario 2: Attacker doesn't have $2
302 http://127.0.0.1/csrf/me/daddy
http://$webserver_ip/
The posted link is a public IP, so Sopel will happily load it and follow the redirect to the private address.
Scenario 3: Attacker has $2, but the above is fixed
haha.bad
haha.bad
to an IP you controlIn the checking stage, Sopel will see the address 1.2.3.4. When performing the request, 127.0.0.1 will be used without validation. (TOCTOU)
Scenario 4: Attacker has $2 and target is IPv6
haha.bad
haha.bad
to the target IPv6 addresshttp://haha.bad/csrf/me/daddy
dns.resolver.resolve()
does not request AAAA records, so any combination of DNS and IPv6 passes validation.Expected behavior
As explained on IRC, this behavior (especially the first two parts) is objectively broken and gives a false sense of security. We should either remove those config options and not pretend, or we should make url.py unable to talk to private IPs.
Environment
.version
: Since before the name "Sopel" to present.Notes
Ping @dgw and @Exirel, who requested this be an issue instead of IRC comments and a PR.
The text was updated successfully, but these errors were encountered: