guest@6admin.io:~$

Bash: IP address obfuscation

An IP address has one “natural” representation (dotted quad: 192.168.1.1), but it has several numeric representations that browsers, SSH clients and log parsers also accept. An IP can be written in pure decimal (3232235777), hexadecimal (0xC0A80101), octal, or mixed (192.168.0x1.1). Logs filtering on “192.168.1.1” do not filter on “3232235777” and that is the obfuscation hole.

The representations

# Pure decimal (uint32)
printf "%d\n" 3232235777
# 3232235777 = 192.168.1.1

# Hexadecimal
printf "0x%X\n" 3232235777
# 0xC0A80101

# Octal
printf "%o\n" 3232235777
# 30052000401

The browser accepts http://3232235777/ exactly like http://192.168.1.1/: it converts the number to dotted quad before connecting. The SSH client too, the FTP client too.

The conversion in bash

From dotted quad to decimal:

ip2dec() {
    local a b c d
    IFS=. read -r a b c d <<< "$1"
    echo $((a * 256**3 + b * 256**2 + c * 256 + d))
}

ip2dec 192.168.1.1
# 3232235777

From decimal to dotted quad:

dec2ip() {
    local ip=$1
    echo "$((ip >> 24 & 255)).$((ip >> 16 & 255)).$((ip >> 8 & 255)).$((ip & 255))"
}

dec2ip 3232235777
# 192.168.1.1

The log filter that misses

An Apache log contains:

3232235777 - - [01/Dec/2008:12:00:00] "GET /admin HTTP/1.1" 200

The filter looking for 192.168.1.1 finds nothing, because the log contains the decimal form. IP obfuscation is a technique to bypass log filters, bypass iptables rules (if the rule matches on the source IP in dotted quad) and bypass log analysis.

The fix

Convert ALL IPs in logs to a single form (dotted quad) before analysis:

# AWK converting decimals to dotted quad
awk '{ if ($1 ~ /^[0-9]+$/ && $1 > 16777216) { ... } }'

Or simpler: normalize logs at ingestion (Logstash, Fluentd, rsyslog with mmnormalize), not at analysis time.