Digbit – a Bit-shifted automatic domain generation for BitSquatting [python]

BitSquatting is not new but it’s relatively new. This type of attack relies on a random bit that switches from 0 to 1 or from 1 to 0 inside a RAM. Because of this even though you try to access domain like, in fact your computer is requesting It’s rare but it happens. It can be caused by a cosmic radiation or overheated memory modules. If You would like to learn more I can recommend Artem’s page.

To make it easier to find a domain that is in a single bit-shift distance (as in Hamming distance) I’ve created a script that is generating all the possibilities.

For example lets search for domains (bit-wise) close to The script output will be: cnn.som cnn.kom cnn.gom cnn.aom cnn.cgm cnn.ckm cnn.cmm cnn.cnm cnn.coe cnn.coi cnn.coo cnn.col

To make it easier to check if particular domain is already registered or not, I’ve made a wrapper script that will execute the python script and for each generated domain it will execute command:

> nslookup domain | grep "NXDOMAIN"

The wrapper script is executed with a single argument that is a domain name. Sample output for

Twitter bitsquatting

Some of those reported as available are obviously false-positive since TLDs like kom don’t really exist. I did not removed them because new TLDs are added from time to time and you might as well have a custom domain setup within your LAN.

The wrapper code:


for i in $( ./ $1);
        dotcheck=$( echo "$i" | grep "\." | wc -l)
        echo -n "$i ";
        check=$(nslookup $i| grep "NXDOMAIN" | wc -l);
        if [[ $check -ne 0 && dotcheck -ne 0 ]];
                echo " < available";
                echo " ";

The Digbit script code:

#!/usr/bin/env python3
import binascii
import re
import os
import sys

def new_text2bin(mtext):
        result = [ bin(ord(ch))[2:].zfill(8) for ch in mtext ]
        return ''.join(result)

def switch_bit(bit, my_list ):
        result_list = my_list[:]
        if result_list[bit] == '1':
                result_list[bit] = '0'
                result_list[bit] = '1'
        return result_list

def generate_similar( domain ):
        domains = []
        domain_list = list(domain)
        for i in range(len(domain)):
                print(switch_bit(i, domain_list))
        return domains

def binstr_to_ascii( binstr ):
        binstr = -len(binstr) % 8 * '0' + binstr
        string_blocks = (binstr[i:i+8] for i in range(0, len(binstr), 8))
        string = ''.join(chr(int(char, 2)) for char in string_blocks)
        return string

if len(sys.argv) != 2:
        sys.exit("Not enough args")

        domain_list = list(new_text2bin(domain))

        for i in range(len(domain_list)):
                new_d = (''.join(switch_bit(i, domain_list)))

                new_d_str = binstr_to_ascii(new_d)
                corect_domain = re.match("^(((([a-z0-9]+){1,63}\.)|(([a-z0-9]+(\-)+[a-z0-9]+){1,63}\.))+){1,255}$", new_d_str + "." )

                if ( corect_domain is not None and len(corect_domain.string) > 1 and (corect_domain.string).index(".") < len(corect_domain.string)-1 ):
                        print(new_d_str, end="\n")

        print(" ")