Many applications these days do network requests on behalf of their users. For example, it is often possible to define webhooks, where users can specify URLs to which a server shall send HTTP requests when certain events occur. Other applications may allow uploading images by URL or they may generate PDFs from HTML rendered server-side, which could contain URLs (see here). In all these examples, users provide input to specify the destinations of server-side network requests.
Filters are required to prevent access to internal systems.
Attackers may otherwise abuse the feature to access resources that are supposed to be inaccessible.
They may attempt to access services local to the server (
other services within internal networks (e.g.,
or instance metadata of cloud hosts on link-local addresses (e.g., EC2 instance metadata at
Thus, the server must validate the input to ensure only an expected range
of IP addresses will ever be contacted.
IP validations can sometimes be bypassed if rare, exotic representations of IP addresses are supplied as input. Not all parsers will properly support rare IP formats. If one parser is used during IP address validation and another when making the actual network request, then if the two disagree it might be that the validator does not block a string that is parsed as a dangerous IP later on.
Such problems appear in popular software from time to time (e.g., GitLab). There are also plenty of CVEs for IP parsing libraries describing failures to parse exotic representations correctly (see, e.g., CVE-2021-2941 for Node’s netmask package, CVE-2021-29921 for Python’s ipaddress package, CVE-2021-29922 for Rust’s parser or CVE-2021-29923 for Go’s net parsers). Lots of reasons to thoroughly test IP address validators if their purpose is to keep people out of your private network ranges. But what are those rare IP formats?
A good starting point is RFC 3986, which describes the syntax of a Uniform Resource Identifier (URI). Besides defining the format everyone is used to, section 7 (security considerations) contains some notes on exotic formats. Find them here. You may also find the man page of inet_aton interesting.
Below, you find a discussion of the various IPv4 address formats I’m aware of. If you know all of it and just want to get list of them for testing then go to the online IP encoder instead. It will generate a number of alternative formats for any IPv4 you enter.
Starting point: Dotted-decimal form
Lets start with defining the normal IPv4 format, just for completeness.
It is a sequence of four decimal numbers called octets, separated by dots.
Octets are 8-bit numbers.
That is, they must be in the range of 0 and 255.
An example is
This is what everybody knows and is used to.
Hexadecimal and octal octets
Octets don’t have to be decimal numbers. You can also write them in hexadecimal and octal form. This is achieved in the following ways:
- Hexadecimal: prefix the octet with
- Octal: prefix the octet with
Use the input box below to try it out.
Type in your IP and it will give you the hexadecimal and octal equivalents of it.
Use them with a tool such as
curl to convince yourself that are in fact all the same.
You can even mix all representations in a single IP address.
For example, you can write
where the first two octets are hexadecimal, the third one is octal and the fourth is decimal.
Curl and many other programs are perfectly able to parse that:
[email protected]:~$ curl -v https://0x8.0X8.010.8 2>&1 | grep 'Connected to' * Connected to 22.214.171.124 (126.96.36.199) port 443 (#0)
If you like, you can insert as many zeros as you want in between the prefixes and the hexadecimal/octal numbers. For example:
- write the octal octet
- write the hexadecimal octet
To see that in action, ping
188.8.131.52 in the following way:
[email protected]:~$ ping 0x0000000000000008.0X8.00000000000000000000010.8 PING 0x0000000000000008.0X8.00000000000000000000010.8 (184.108.40.206): 56 data bytes 64 bytes from 220.127.116.11: icmp_seq=0 ttl=112 time=15.293 ms 64 bytes from 18.104.22.168: icmp_seq=1 ttl=112 time=14.347 ms
Less than three dots
You don’t need exactly four octets to write an IPv4 address. Rather, you can use at most four numbers. If you want to use fewer, you have to combine the octets from right to left to a single, bigger number. Best explained using an example.
Say you want to write the IP address
22.214.171.124 with two dots and three numbers.
This is what you have to do:
Leave the first two octets
Now combine the last two octets
3.4 to one number.
Written as 8-bit binary numbers, octet
Combined to a 16-bit number, you get
772 in decimal form.
So you can write the IP
126.96.36.199 also as
This actually works all the way until only one 32-bit number is left.
So you can write
1.131844 or just
Again, use the following input box to type your IP and see all the different representations below:
Combining the two variations
You probably expect it at this point, but it shall be mentioned explicitly for completeness:
of course you can also use hexadecimal or octal numbers when you use less than four numbers.
For example, to write
188.8.131.52, you can use three numbers all in different formats:
0x8.010.2056. Convince yourself by pinging it:
[email protected]:~$ ping 0x8.010.2056 PING 0x8.010.2056 (184.108.40.206): 56 data bytes 64 bytes from 220.127.116.11: icmp_seq=0 ttl=112 time=12.784 ms 64 bytes from 18.104.22.168: icmp_seq=1 ttl=112 time=21.280 ms