Friday, July 29, 2011

HID VertX V2000 Card Number Cache Tool (VertX_CacheQuery)

Last Article I discovered the cache on the HID VertX V2000, and learned that it contains all of the provisioned cards (and some non-provisioned cached cards). So if you gain access to the V2000, you can read all of the valid cards from this cache and emulate those values to gain physical access to a location.

Last time i used a hexeditor to pull the data.. that did the job, but the none of the fields were really defined or anything. This tool will do some of that for you.

You can either transfer the /mnt/flash/config/AccessDB and /mnt/flash/config/IdentDB files via ftp to your linux box, and run VertX_CacheQuery or compile VertX_CacheQuery.c for the VertX V2000 and transfer the binary over to the V2000 and run it from there.

Here's your help:


# ./VertX_CacheQuery -h
HID VertX V2000 IdentDB/AccessDB Tool v0.1
By brad a.
---------------------------------
Options:
-i ID Value
-f Path to IdentDB (default: /mnt/flash/config/IdentDB)
-a Path to AccessDB (default: /mnt/flash/config/AccessDB
-p Dump data from AccessDB and IdentDB
Usage:
./VertX_CacheQuery -p
./VertX_CacheQuery -i 00000000 (NOT CURRENTLY WORKING)



and here is sample output:

# ./VertX_CacheQuery -p -f IdentDB -a AccessDB
HID VertX V2000 IdentDB/AccessDB Tool v0.1
By brad a.
---------------------------------
Using non-default IdentDB Path
Using non-default AccessDB Path
AccessDB Location: AccessDB
IdentDB Location: IdentDB
IdentDB Raw:

Entry 0:00263f9500000000000000000000000001000000fe00000000000000
Entry 1:00263f9600000000000000000000000003000000fe00000001000000
Entry 2:00263f9f00000000000000000000000005000000fe00000001000000
Entry 3:00263f8e00000000000000000000000007000000fe00000001000000
Entry 4:00263fa900000000000000000000000009000000fe00000000000000
Entry 5:00263f9c0000000000000000000000000b000000fe00000000000000
Entry 6:00

IdentDB Parsed:
Entry 0:
ID:00 26 3f 95 00 00
IdentDB Entry: 01
Enabled: Yes! (00)
Entry 1:
ID:00 26 3f 96 00 00
IdentDB Entry: 03
Enabled: No (01)
Entry 2:
ID:00 26 3f 9f 00 00
IdentDB Entry: 05
Enabled: No (01)
Entry 3:
ID:00 26 3f 8e 00 00
IdentDB Entry: 07
Enabled: No (01)
Entry 4:
ID:00 26 3f a9 00 00
IdentDB Entry: 09
Enabled: Yes! (00)
Entry 5:
ID:00 26 3f 9c 00 00
IdentDB Entry: 0b
Enabled: Yes! (00)

AccessDB Raw:

Entry 0:010000000f000000020000000000000000000000000000002855254eff0bbd72000000000000000000000000
Entry 1:030000000f000000020000000000000000000000000000002495254eff0bbd72000000000000000008000000
Entry 2:050000000f00000002000000000000000000000000000000c46c264eff0bbd72000000000000000008000000
Entry 3:070000000f000000020000000000000000000000000000006076264eff0bbd72000000000000000008000000
Entry 4:090000000f00000003000000000000000000000000000000c09d264eff0bbd72000000000000000020000000
Entry 5:0b0000000f00000004000000000000000000000000000000bca1264eff0bbd72000000000000000020000000
Entry 6:00

AccessDB Parsed:
Entry 0:
AccessDB Entry: 01
Door Access Rights: 02
Entry 1:
AccessDB Entry: 03
Door Access Rights: 02
Entry 2:
AccessDB Entry: 05
Door Access Rights: 02
Entry 3:
AccessDB Entry: 07
Door Access Rights: 02
Entry 4:
AccessDB Entry: 09
Door Access Rights: 03
Entry 5:
AccessDB Entry: 0b
Door Access Rights: 04




and the source:

# cat VertX_CacheQuery.c
/*
 VertX_CacheQuery -
  tool that queries the cache on a HID VertX V2000
  By Brad Antoniewicz
*/


#include <stdio.h>
#include <string.h>
#include <stdint.h>

float VERSION=0.1;

struct rec {
 uint8_t position;
};


void help(char name[]) {
 printf("Options:\n");
 printf("\t-i <ID>\t\tID Value\n");
 printf("\t-f <IdentDB>\tPath to IdentDB (default: /mnt/flash/config/IdentDB)\n");
 printf("\t-a <AccessDB>\tPath to AccessDB (default: /mnt/flash/config/AccessDB\n");
 printf("\t-p\t\tDump data from AccessDB and IdentDB\n");
 printf("Usage:\n");
 printf("\t %s -p\n",name);
 printf("\t %s -i 00000000 (NOT CURRENTLY WORKING)\n",name);

}

/*
Sample IdentDB Entry
 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
00 26 3F 95 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 FE 00 00 00 00 00 00 00

Field 0 - 3 = Card ID
Field 16 = Entry Number
Field 20 = Seems to remain constant (FE)
Field 24 = Enabled(00)/Disababled(01)?
*/
int readident(char *ident_file) {
 int    LENGTH_CARDID=6,
  LENGTH_ENTRY=28,
  FIELD_CARDID=0,
  FIELD_ENTRY=16,
  FIELD_ENABLED=24,
  OFFSET=0;
 FILE *ident_ptr;
 int counter=1,location,entries=0,x,y;
 struct rec my_record;

 ident_ptr = fopen(ident_file,"rb");
 if (!ident_ptr) {
  printf("ERROR: Could not open %s\n",ident_file);
  return 1;
 }
 printf("IdentDB Raw:\n\t");
 while (!feof(ident_ptr)) {
  if (counter == 1 || counter % LENGTH_ENTRY == 1) {
        printf("\n\tEntry %d:",entries);
        entries++;
  }
  fread(&my_record,sizeof(struct rec),1,ident_ptr);
  printf("%02x",my_record.position);
  counter++;
 }
 fseek(ident_ptr,0,SEEK_CUR);
 printf("\n\nIdentDB Parsed:\n");
 counter = 1;
 for(x=0; x < entries - 1; x++) {
  printf("\tEntry %d:\n",x);

  printf("\t\tID:");
  fseek(ident_ptr,OFFSET + FIELD_CARDID ,SEEK_SET);
  for(y=1; y<=LENGTH_CARDID; y++) {
        fread(&my_record,sizeof(struct rec),1,ident_ptr);
        printf("%02x ",my_record.position);
  }
  printf("\n");

  fseek(ident_ptr,OFFSET + FIELD_ENTRY, SEEK_SET);
  fread(&my_record,sizeof(struct rec),1,ident_ptr);
  printf("\t\tIdentDB Entry: %02x\n",my_record.position);

                fseek(ident_ptr,OFFSET + FIELD_ENABLED, SEEK_SET);
                fread(&my_record,sizeof(struct rec),1,ident_ptr);
  if (my_record.position == 00)
        printf("\t\tEnabled: Yes! (%02x)\n",my_record.position);
  else if (my_record.position == 01)
        printf("\t\tEnabled: No (%02x)\n",my_record.position);
  else
        printf("\t\tEnabled: Unknown Status!(%02x)\n",my_record.position);
  OFFSET = OFFSET + LENGTH_ENTRY;

 }
 printf("\n");
 fclose(ident_ptr);

}

/*
Sample Access DB Entry
 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
01 00 00 00 0F 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 55 25 4E FF 0B BD 72 00 00 00 00 00 00 00 00 00 00 00 00
Field 0 = Entry Number (Matches IdentDB)
Field 4 = Seems to remain constant (0F)
Field 8 = Door Access (Defined in /mnt/flash/config/DoorGroups)
*/

int readaccess(char *access_file) {
        int     LENGTH_CARDID=6,
                LENGTH_ENTRY=44,
                FIELD_CARDID=0,
                FIELD_ENTRY=0,
                FIELD_DOORS=8,
                OFFSET=0;
        FILE *access_ptr;
        int counter=1,location,entries=0,x,y;
        struct rec my_record;

        access_ptr = fopen(access_file,"rb");
        if (!access_ptr) {
                printf("ERROR: Could not open %s\n",access_file);
                return 1;
        }
        printf("AccessDB Raw:\n\t");
        while (!feof(access_ptr)) {
                if (counter == 1 || counter % LENGTH_ENTRY == 1) {
                        printf("\n\tEntry %d:",entries);
                        entries++;
                }
                fread(&my_record,sizeof(struct rec),1,access_ptr);
                printf("%02x",my_record.position);
                counter++;
        }
        fseek(access_ptr,0,SEEK_CUR);
        printf("\n\nAccessDB Parsed:\n");
        counter = 1;
        for(x=0; x < entries - 1; x++) {
                printf("\tEntry %d:\n",x);

                fseek(access_ptr,OFFSET + FIELD_ENTRY, SEEK_SET);
                fread(&my_record,sizeof(struct rec),1,access_ptr);
                printf("\t\tAccessDB Entry: %02x\n",my_record.position);

                fseek(access_ptr,OFFSET + FIELD_DOORS, SEEK_SET);
                fread(&my_record,sizeof(struct rec),1,access_ptr);
  printf("\t\tDoor Access Rights: %02x\n",my_record.position);

                OFFSET = OFFSET + LENGTH_ENTRY;

        }
        printf("\n");
        fclose(access_ptr);

}

int main(int argc, char *argv[]) {
 int c=0, x=0, y=0, l=0, ch=0, parse=0;
 int buffsize=128;
 char card_val[buffsize + 1];
 char accessDB[129] = "/mnt/flash/config/AccessDB";
 char identDB[129] = "/mnt/flash/config/IdentDB";

 printf("HID VertX V2000 IdentDB/AccessDB Tool v%1.1f\n",VERSION);
 printf("By brad a.\n");
 printf("---------------------------------\n");
 if (argc < 2 ) {
  help(argv[0]);
  return 0;
 }

 for ( x = 0; x < argc; x++) {
  switch( (int)argv[x][0]) {
        case '-':
                l = strlen(argv[x]);
                for ( y = 1; y < l; ++y) {
                        ch = (int)argv[x][y];
                        switch(ch) {
                                case 'i':
                                        if (strlen(argv[x+1]) < buffsize) {
                                                strncpy(card_val,argv[x+1],buffsize);
                                                printf("Using Card Value: %s\n",card_val);
                                                printf("THIS DOESNT WORK ATM!\n");
                                        }
                                        break;
                                case 'f':
                                        if (strlen(argv[x+1]) < buffsize) {
                                                strncpy(identDB,argv[x+1],buffsize);
                                                printf("Using non-default IdentDB Path\n");
                                        }
                                        break;
                                case 'a':
                                        if (strlen(argv[x+1]) < buffsize) {
                                                strncpy(accessDB, argv[x+1], buffsize);
                                                printf("Using non-default AccessDB Path\n");
                                        }
                                        break;
                                case 'p':
                                        parse=1;
                                        break;
                                default:
                                        help(argv[0]);
                                        return 1;
                        }
                }
        break;
  }
 }
 if (strlen(card_val) < 6 && !parse) {
  printf("ERROR: Card Value must be at least 6 hex chars long\n");
  return 1;
 }

 printf("AccessDB Location: %s\n",accessDB);
 printf("IdentDB Location: %s\n",identDB);
 if (parse) {
  readident(identDB);
  readaccess(accessDB);
 }



  return 0;
}

No comments:

Post a Comment