# Bypassing blacklists based on IPy

IPy's iptype() misclassifies octal-encoded IPs like 0177.0000.0000.0001 as PUBLIC, letting SSRF blacklists be bypassed to reach 127.0.0.1.

- Payout: $500
- Severity: medium
- Program: Prezi, autocracy (python-ipy)
- Credited: Nicolas Grégoire
- Disclosed: 2014-10-15
- Write-up quality: 7/10
- Original: https://www.agarri.fr/blog/archives/2014/10/15/bypassing_blacklists_based_on_ipy/index.html
- Library page: https://bugbountylibrary.com/r/blog%3Aagarri-fr-blog-archives-2014-10-15-bypassing-blacklists-based-on-ipy-index-html
- Tags: domain:web impact:internal-access kind:bounty platform:blog sev:medium tech:python technique:fuzzing technique:parser-differential vuln:ssrf

**Target:** Python IPy library used in URL-to-IP blacklist filter (urllib2 conversion backend)
**Root cause:** IPy.IP().iptype() parses dotted addresses as decimal bytes, so octal-encoded octets like 0177 are misread and fall through to the 'PUBLIC' fallback, while urllib2 resolves them to the real private address.
**Steps:**
1. Obtain the blacklist code: `IPy.IP(ip_address).iptype() == 'PRIVATE'`
2. Enumerate urllib2-supported IP encodings: integer, hex, dotted-hex, octal
3. Test `IPy.IP('0177.0000.0000.0001').iptype()` -> returns 'PUBLIC'
4. Confirm urllib2 resolves `0177.0000.0000.0001` to 127.0.0.1
5. Submit URL with octal-encoded host to bypass the private-IP filter and reach internal services
**How found:** Noticed the blacklist relied on IPy's iptype() with 'PUBLIC' fallbacks, hypothesized a parser differential between IPy and urllib2, then fuzzed five loopback encodings and found octal misclassified as PUBLIC.
**Exploitation:** Attacker supplies a URL whose host is octal-encoded (e.g. 0177.0000.0000.0001) to the conversion backend; the IPy-based blacklist classifies it PUBLIC while urllib2 connects to 127.0.0.1, enabling SSRF to internal/loopback addresses.
**Insight:** When a blacklist uses a library's classification function, fuzz alternate textual encodings of the same address (octal, hex, integer, dotted variants) and compare against what the actual HTTP client resolves — any disagreement is a bypass.
