"""Convenience wrapper around `requests.Session` set up for `advocate`ing""" def__init__(self, *args, **kwargs): self.validator = kwargs.pop("validator", self.DEFAULT_VALIDATOR) adapter_kwargs = kwargs.pop("_adapter_kwargs", {})
# `Session.__init__()` calls `mount()` internally, so we need to allow # it temporarily self.__mountAllowed = True RequestsSession.__init__(self, *args, **kwargs)
# Drop any existing adapters self.adapters = OrderedDict()
import functools import fnmatch import re import six
import netifaces
from .exceptions import NameserverException from .packages import ipaddress
defcanonicalize_hostname(hostname): """Lowercase and punycodify a hostname""" # We do the lowercasing after IDNA encoding because we only want to # lowercase the *ASCII* chars. # TODO: The differences between IDNA2003 and IDNA2008 might be relevant # to us, but both specs are damn confusing. return six.text_type(hostname.encode("idna").lower(), 'utf-8')
defdetermine_local_addresses(): """Get all IPs that refer to this machine according to netifaces""" ips = [] for interface in netifaces.interfaces(): if_families = netifaces.ifaddresses(interface) for family_kind in {netifaces.AF_INET, netifaces.AF_INET6}: addrs = if_families.get(family_kind, []) for addr in (x.get("addr", "") for x in addrs): if family_kind == netifaces.AF_INET6: # We can't do anything sensible with the scope here addr = addr.split("%")[0] ips.append(ipaddress.ip_network(addr)) return ips
defadd_local_address_arg(func): """Add the "_local_addresses" kwarg if it's missing IMO this information shouldn't be cached between calls (what if one of the adapters got a new IP at runtime?,) and we don't want each function to recalculate it. Just recalculate it if the caller didn't provide it for us. """ @functools.wraps(func) defwrapper(self, *args, **kwargs): if"_local_addresses"notin kwargs: ifself.autodetect_local_addresses: kwargs["_local_addresses"] = determine_local_addresses() else: kwargs["_local_addresses"] = [] return func(self, *args, **kwargs) return wrapper
classAddrValidator(object): _6TO4_RELAY_NET = ipaddress.ip_network("192.88.99.0/24") # Just the well known prefix, DNS64 servers can set their own # prefix, but in practice most probably don't. _DNS64_WK_PREFIX = ipaddress.ip_network("64:ff9b::/96") DEFAULT_PORT_WHITELIST = {80, 8080, 443, 8443, 8000}
def__init__( self, ip_blacklist=None, ip_whitelist=None, port_whitelist=None, port_blacklist=None, hostname_blacklist=None, allow_ipv6=False, allow_teredo=False, allow_6to4=False, allow_dns64=False, autodetect_local_addresses=True, ): ifnot port_blacklist andnot port_whitelist: # An assortment of common HTTPS? ports. port_whitelist = self.DEFAULT_PORT_WHITELIST.copy() self.ip_blacklist = ip_blacklist orset() self.ip_whitelist = ip_whitelist orset() self.port_blacklist = port_blacklist orset() self.port_whitelist = port_whitelist orset() # TODO: ATM this can contain either regexes or globs that are converted # to regexes upon every check. Create a collection that automagically # converts them to regexes on insert? self.hostname_blacklist = hostname_blacklist orset() self.allow_ipv6 = allow_ipv6 self.allow_teredo = allow_teredo self.allow_6to4 = allow_6to4 self.allow_dns64 = allow_dns64 self.autodetect_local_addresses = autodetect_local_addresses
# The whitelist should take precedence over the blacklist so we can # punch holes in blacklisted ranges ifany(addr_ip in net for net inself.ip_whitelist): returnTrue
ifany(addr_ip in net for net inself.ip_blacklist): returnFalse
ifany(addr_ip in net for net in _local_addresses): returnFalse
if addr_ip.version == 4: ifnot addr_ip.is_private: # IPs for carrier-grade NAT. Seems weird that it doesn't set # `is_private`, but we need to check `not is_global` ifnot ipaddress.ip_network(addr_ip).is_global: returnFalse elif addr_ip.version == 6: # You'd better have a good reason for enabling IPv6 # because Advocate's techniques don't work well without NAT. ifnotself.allow_ipv6: returnFalse
# v6 addresses can also map to IPv4 addresses! Tricky! v4_nested = [] if addr_ip.ipv4_mapped: v4_nested.append(addr_ip.ipv4_mapped) # WTF IPv6? Why you gotta have a billion tunneling mechanisms? # XXX: Do we even really care about these? If we're tunneling # through public servers we shouldn't be able to access # addresses on our private network, right? if addr_ip.sixtofour: ifnotself.allow_6to4: returnFalse v4_nested.append(addr_ip.sixtofour) if addr_ip.teredo: ifnotself.allow_teredo: returnFalse # Check both the client *and* server IPs v4_nested.extend(addr_ip.teredo) if addr_ip inself._DNS64_WK_PREFIX: ifnotself.allow_dns64: returnFalse # When using the well-known prefix the last 4 bytes # are the IPv4 addr v4_nested.append(ipaddress.ip_address(addr_ip.packed[-4:]))
ifnotall(self.is_ip_allowed(addr_v4) for addr_v4 in v4_nested): returnFalse
# fec0::*, apparently deprecated? if addr_ip.is_site_local: returnFalse else: raise ValueError("Unsupported IP version(?): %r" % addr_ip)
# 169.254.XXX.XXX, AWS uses these for autoconfiguration if addr_ip.is_link_local: returnFalse # 127.0.0.1, ::1, etc. if addr_ip.is_loopback: returnFalse if addr_ip.is_multicast: returnFalse # 192.168.XXX.XXX, 10.XXX.XXX.XXX if addr_ip.is_private: returnFalse # 255.255.255.255, ::ffff:XXXX:XXXX (v6->v4) mapping if addr_ip.is_reserved: returnFalse # There's no reason to connect directly to a 6to4 relay if addr_ip inself._6TO4_RELAY_NET: returnFalse # 0.0.0.0 if addr_ip.is_unspecified: returnFalse
# It doesn't look bad, so... it's must be ok! returnTrue
def_hostname_matches_pattern(self, hostname, pattern): # If they specified a string, just assume they only want basic globbing. # This stops people from not realizing they're dealing in REs and # not escaping their periods unless they specifically pass in an RE. # This has the added benefit of letting us sanely handle globbed # IDNs by default. ifisinstance(pattern, six.string_types): # convert the glob to a punycode glob, then a regex pattern = fnmatch.translate(canonicalize_hostname(pattern))
hostname = canonicalize_hostname(hostname) # Down the line the hostname may get treated as a null-terminated string # (as with `socket.getaddrinfo`.) Try to account for that. # # >>> socket.getaddrinfo("example.com\x00aaaa", 80) # [(2, 1, 6, '', ('93.184.216.34', 80)), [...] no_null_hostname = hostname.split("\x00")[0]
returnany(re.match(pattern, x.strip(".")) for x in (no_null_hostname, hostname))
defis_hostname_allowed(self, hostname): # Sometimes (like with "external" services that your IP has privileged # access to) you might not always know the IP range to blacklist access # to, or the `A` record might change without you noticing. # For e.x.: `foocorp.external.org`. # # Another option is doing something like: # # for addrinfo in socket.getaddrinfo("foocorp.external.org", 80): # global_validator.ip_blacklist.add(ip_address(addrinfo[4][0])) # # but that's not always a good idea if they're behind a third-party lb. for pattern inself.hostname_blacklist: ifself._hostname_matches_pattern(hostname, pattern): returnFalse returnTrue
@add_local_address_arg defis_addrinfo_allowed(self, addrinfo, _local_addresses=None): assert(len(addrinfo) == 5) # XXX: Do we care about any of the other elements? Guessing not. family, socktype, proto, canonname, sockaddr = addrinfo
# The 4th elem inaddrinfo may either be a touple of two or four items, # depending on whether we're dealing with IPv4 or v6 iflen(sockaddr) == 2: # v4 ip, port = sockaddr eliflen(sockaddr) == 4: # v6 # XXX: what *are* `flow_info` and `scope_id`? Anything useful? # Seems like we can figure out all we need about the scope from # the `is_<x>` properties. ip, port, flow_info, scope_id = sockaddr else: raise ValueError("Unexpected addrinfo format %r" % sockaddr)
# Probably won't help protect against SSRF, but might prevent our being # used to attack others' non-HTTP services. See # http://www.remote.org/jochen/sec/hfpa/ ifself.port_whitelist and port notinself.port_whitelist: returnFalse if port inself.port_blacklist: returnFalse
ifself.hostname_blacklist: ifnot canonname: raise NameserverException( "addrinfo must contain the canon name to do blacklisting " "based on hostname. Make sure you use the " "`socket.AI_CANONNAME` flag, and that each record contains " "the canon name. Your DNS server might also be garbage." )
from flask import Flask, redirect app = Flask(__name__) i = 0 @app.route('/') defindex(): global i if i == 0: i += 1 return'Nothing to see here' else: return redirect('http://localhost/flag') if __name__ == '__main__': app.run()
if (isset($_POST['admin']) andisset($_POST['root_pwd'])) { if ($_POST['admin'] == $_POST['root_pwd']) echo'<p>The level 2 can not pass!</p>'; // START FORM PROCESSING elseif (sha1($_POST['admin']) === sha1($_POST['root_pwd'])){ echo"here is level 3,do you kown how to overcome it?"; ... } }