SRI International


Conficker C Active P2P Scanner



Computer Science Laboratory
SRI International
333 Ravenswood Avenue
Menlo Park CA 94025 USA


Download

Version 0.1B:   Conficker_C_P2P_Scanner.C

author: Vinod Yegneswaran
compiled and tested on -  Gnu gcc ver 4.2.2, running Linux, little endian only.

Acknowledgements:  thanks to Fabien Perigaud - CERT Lexsi, France

README

Conficker_C_P2P_Scanner is an network-based active scanner application that scans a subnet for Conficker C infected hosts.

Usage:   

Conficker_C_P2P_Scanner
[-t ms waittime] [-v (verbose)] <low-address>  <high-address>

      low|high-address    -  specifies the start and end address ranges to be scanned

      ex:     % Conficker_C_P2P_Scanner  192.168.7.0  192.168.99.255
      will scan all addresses in subnets 192.168.[7-99]

Detection Synopsis:

All Conficker C hosts perform outbound P2P scanning in search of other C infected peers.   Each C-infected host opens four network ports  in listen mode:  2 TCP ports and 2 UDP.  These four listen ports are derived from a function of the host's own IP address and the current  epoch week. To illustrate the algorithm used to compute C's P2P client listen ports, we include a source code example C implementation, which we reverse-engineered from a Conficker C binary captured on 5 March 2009.

Conficker_C_P2P_Scanner will scan the low-thru-high address range in search of IP addresses that have established TCP listen ports on their associated Conficker C P2P listen ports.  An alarm is provided each time a host is found to be listening on its P2P listen port.



Good Luck.
SRI International


Example Conficker C P2P Port Generation Algorithm

/*  Copyright: SRI International
    authors:   Hassen Saidi, Vinod Yegneswaran, and
Drew Dean, 31 March 2009.
    Acknowledgments: thanks to David Fifield from Bam Software for identifying
    the purpose of portBlacklist.

*/
#include <stdio.h>

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

typedef union {
  int16_t s16[8];
  uint16_t u16[8];
  int32_t s32[4];
} result_t;

typedef union {
  int64_t s64;
  int32_t s32[2];
  uint32_t u32[2];
  int16_t s16[4];
} var_t;

uint32_t portBlacklist[64] =
  {
    0xffffffff, 0xffffffff,     0xf0f6bfbb,     0xbb5a5ff3,
    0xf3977011, 0xeb67bfbf,     0x5f9bfac8,     0x34d88091,
    0x1e2282df, 0x573402c4,     0xc0000084,     0x03000209,
    0x01600002, 0x00005000,     0x801000c0,     0x00500040,
    0x000000a1, 0x01000000,     0x01000000,     0x00022a20,
    0x00000080, 0x04000000,     0x40020000,     0x88000000,
    0x00000180, 0x00081000,     0x08801900,     0x00800b81,
    0x00000280, 0x080002c0,     0x00a80000,     0x00008000,
    0x00100040, 0x00100000,     0x00000000,     0x00000000,
    0x10000008, 0x00000000,     0x00000000,     0x00000004,
    0x00000002, 0x00000000,     0x00040000,     0x00000000,
    0x00000000, 0x00000000,     0x00410000,     0x82000000,
    0x00000000, 0x00000000,     0x00000001,     0x00000000,
    0x00000000, 0x00000000,     0x00000000,     0x00000000,
    0x00000000, 0x00000000,     0x00000000,     0x00000000,
    0x00000000, 0x00000000,     0x00000008,     0x80000000
  };

#define IS_PORT_BLACKLISTED(x) (1 << ((x >> 5) & 0x1F)) & portBlacklist[x >> 10]

/* NB: the portgen() function below is endian-dependent, and reverse-engineered
   for a little-endian (e.g. x86, VAX, Alpha, etc.) machine.  Changes will be
   required
for the array offsets in the unions to run on a big-endian (e.g. most
   SPARC, Power(PC), MIPS, etc.)
machine.  Other than the endian issue, this
   implementaiton should be portable. */


int portgen(int ip, result_t *res, int week)
{
  var_t v;      
  int64_t KONST = 0x15A4E35;
  int i;
        
  memset(res, 0, sizeof(result_t));
  v.s32[0] = ~ip;

   /* Generate fixed ports */
  do {
    do {
      v.s64 = KONST * v.u32[0] + 1;
      res->s16[0] ^= v.s16[2];
     
      for (i=1; i < 10; i++) {
        v.s64 = KONST * v.u32[0] + 1;
        res->s16[(i%2)*2] ^= v.s32[1] >> i;
      }

    } while (IS_PORT_BLACKLISTED(res->s32[0]));
                
  } while (IS_PORT_BLACKLISTED(res->s32[1]) || res->s32[0] == res->s32[1]);

  v.s32[0] = week ^ v.s64;


   /* Generate week-dependent ports  */
  do {
    do {
      v.s64 = KONST * v.u32[0] + 1;
      res->s16[4] ^= v.s16[2];
         
      for (i=1; i < 10; i++) {
        v.s64 = KONST * v.u32[0] + 1;
        res->s16[(i%2)*2 + 4] ^= v.s32[1] >> i;
      }
     
    } while (IS_PORT_BLACKLISTED(res->s32[2]));
                   
  } while (IS_PORT_BLACKLISTED(res->s32[3]) || res->s32[2] == res->s32[3] ||
           res->s32[0] == res->s32[2] || res->s32[1] == res->s32[2] ||
           res->s32[0] == res->s32[3] || res->s32[1] == res->s32[3]);
 
  return v.s64;
}

int main(int argc, char** argv) {
  int a1,a3;
  result_t res; 
  int i, rc;
        
  if (argc != 3) {
    printf("usage: conficker_ports <ip addr> <epoch week>\n");
    exit(0);
  }
        
  a1 = inet_addr(argv[1]);
  a3 = atoi(argv[2]);
        
  rc=portgen(a1, &res, a3);
  printf("ports are TCP (fixed), UDP (fixed), TCP (week-dependent), UDP
         (week-dependent)\n");

      
  for (i=0;i<8;i++) {
    if (res.u16[i])
      printf("%d\t",  res.u16[i]);
  }
  printf("\n");
  return 0;
}



Acknowledgments


We gratefully thank the  National Science Foundation (NSF) and the Army Research Office (ARO) for their sponsorship of this research activity.