Current botnets are not immune to legal attacks against the DNS infrastructure of their Command and Control (C&C) servers. While this is good news to spam fighters and every respectable netizen, it is bad news to those who would use botnet-based techniques to disseminate useful information in a hostile environment (like, say, whistle blowers, dissidents, file sharers, …). Fortunately — or unfortunately, depending on how we look at it — those legal attacks are easily circumvented.

How botnets work

Every zombie in a botnet needs to contact its C&C server every now and then to fetch updates or instructions. Obviously, hard coding a set of IP addresses or DNS names would be silly. Not only does it provide evidence, it paints on those addresses a big target sign as well. It would be just a matter of time until they are taken down or firewalled at the backbone level, and the zombies would be orphaned.

Botnet authors have thus come up with a more resilient algorithm. Instead of hard coding, they generate the names of the C&C servers with a pseudo-random generator. This is the pseudo-code:

def get_c_and_c_names:
    "Generate a list of current C&C DNS names."
    c_and_c = []
    while len(c_and_c) < 5:
        name = create_random_domain_name(int(time.time()))
        if test_connectivity_to_new_name(name):
            c_and_c.append(name)
    return c_and_c

The basic idea is simple: the domain names of the C&C servers are generated on-the-fly from a pseudo-random sequence, which depends on the time of day. Botnet operators know the algorithm that creates those pseudo-random domains, and can create (registrer) those domains on an as-needed basis ahead of time. When the time has come, the zombies will connect to a seemingly random domain that has already been registered and populated with a set of C&C nodes.

This strategy is somewhat more robust against legal attacks, because the addresses of the command centers change constantly (say, every few weeks or months). Botnet fighters can always take down a couple of domains, but since the list of pseudo-random domains is potentially infinite (or, more precisely, very long modulo some huge number determined by the pseudo-random number generator), botnet fighters need to constantly take down or preemptively lock new domains as they become current.

A more resilient algorithm

The biggest drawback of the previous algorithm was that the whole list of pseudo-random domains is known in advance, both by the zombies (and thus botnet fighters) and botnet operators. Every botnet fighter worth her salt can pre-compute that list, or rather a prefix of that list that would last long enough to take down the zombies for years. She can then get a court order to force the registry (or registries) to preemptively lock all those domains ahead of time, before they get registered by the botnet operators.

Thus, a more resilient algorithm would obviously introduce more dynamism in the pseudo-random sequence. Instead of seeding the RNG with the same value every time, the zombies could periodically contact their current C&C and fetch a new seed for the sequence:

def handshake_with_c_and_c(c_and_c_names):
    "Establish (encrypted) connection to the C and C server."
    connection = None
    for server_name in c_and_c_names:
        connection = ssl_connect(server_name, credentials)
        if connection:
            new_seed = connection.fetch_new_seed()
            persistently_save_new_seed(new_seed)
            break
    return connection

The new seed would then be used by the function that generates random names:

def create_random_domain_name(parameter):
    "Create a random domain name based on some parameter."
    if not_yet_seeded:
        seed = load_seed_from_persistent_storage()
        rng.seed(seed)
        not_yet_seeded = False
    random_name = create_random_dns_name(rng.getrandom(), parameter)
    return random_name

In other words, the zombies can have the seed for the random sequence periodically updated by the C&C servers, should the botnet operator think that their current list of domains is about to be compromized or shut down.

Pros and Cons

On the plus side, this algorithm is a lot more robust than the one with the fixed seed, because it allows botnet operators to change the sequence as soon as they notice that some of their domains are being closed on behalf of a spam fighter.

On the minus side, this algorithm isn’t perfect: if a spam fighter manages to take off all C&C servers and a long prefix of future domains off the net, the zombies sharing the same seed will be orphaned.

Botnet operators should thus fragment their zombie farm into some subsets that would share different seeds. Say, they control 100,000 zombies. By serving 10 different new seeds, they would get 10 different lists of future domains. Even if one such current list was taken down by a botnet fighter, the botnet would only lose 10% of its capacity.

Of course, some basic precautions should be taken by the C&C, like SSL-encrypting the connections of the zombies, to prevent botnet fighters from hijacking the seed-reset functionality.

Future C&C could be P2P and distributed

Future botnet research could focus on distributing the C&Cs themselves across zombies. Botnet operators could then simply wait to become infected by their own virus, and as soon as that happens, they would have a key to the whole P2P-organized botnet which could use DHT (distributed hash tables) to find each others. Since only botnet operators will have the secret key of unlock the endless replicated command and control functionality of the zombies, botnet fighters would be hard pressed to come up with an effective counter-measure.

This may seem like a wet dream for botnet operators, but the fact that zombies in a P2P botnet find each other with DHT is also their heel of Achilles: botnet fighters could exploit the same technique to precisely pinpoint all infected nodes, and could take preventive action to block them all at the network management level. Sure, the C&C code could be encrypted and unlocked only by a “legitimate” botnet operator, so that tracing the other zombies could still prove hard for the botnet fighter. All this, botnet programmers have to consider with a lot of careful thinking before implementing and releasing a distributed C&C botnet in the wild.

That’s why I think that truly distributed C&Cs won’t be seen in the wild for some time, despite their interesting resilient properties.