Proxmark3 community

Research, development and trades concerning the powerful Proxmark3 device.

Remember; sharing is caring. Bring something back to the community.


"Learn the tools of the trade the hard way." +Fravia

You are not logged in.

Announcement

Time changes and with it the technology
Proxmark3 @ discord

Users of this forum, please be aware that information stored on this site is not private.

#1 2020-01-01 12:29:35

randomdude42
Contributor
Registered: 2019-12-31
Posts: 3

Generating UIDs of Indala/Hedengren cards

I'll cut to the chase: this is somewhat working way of generating Hedengren card UIDs for "cloning." Works for me, but I can't guarantee if it works for you (or every time), but I'll leave my notes here for anyone to play around.

There's been a few similar discussions earlier on this forum about Indala's format: Is it possible to generate Indala UID from number printed on badges?, Understanding Indala Format

Here's my scenario: our facilities use mostly Indala FP3511A/14389 readers and cards with Indala logo + "E8" on it. Labels on readers mention format as "Heden-2L" and other access control hardware came from Hedengren. A local company installed it, we own and operate the system, but if we want new/replacement cards for example, we need to turn to the company which is very happy to charge a lot. We could ask other companies elsewhere, but since we don't know a lot about internals of access control systems, what exactly we're supposed to ask...

Therefore received a PM3 on Monday to clone cosmetically bad cards to new ones, etc. Learned that Indalas can be cloned to T5577 cards so had one to try it out -- it did and the card worked on facility readers. Nice! We also had one USB RFID reader for that 14389 format(?) from RF IDeas laying around so figuring out how to generate UIDs sounded like a plan: generate UID, put it into black box and see what comes out.

So, took one UID from an unused & low-number card, changed one bit at a time, programmed modified UID to a T5577 card and tried what comes out of the USB reader: if the card is valid, it'll spit out card number in plain text -- facility code too, if reader is configured that way. Yeah, I could've used indala sim on iceman's firmware instead of a card in the middle, but this way wasn't too much of a problem.

A zero card turned out to be A000000088800903. The rest of the bits for card number turned out to be like this:

    0 A000000088800903 1010000000000000000000000000000010001000100000000000100100000011
    1 A000000089000903 101000000000000000000000000000001000100x000000000000100100000011
    2 A000000088400903 10100000000000000000000000000000100010000x0000000000100100000011
    4 A000000088040903 101000000000000000000000000000001000100000000x000000100100000011
    8 A000000088020903 1010000000000000000000000000000010001000000000x00000100100000011
   16 A000000088100903 1010000000000000000000000000000010001000000x00000000100100000011
   32 A000000088800912 10100000000000000000000000000000100010001000000000001001000x0010
   64 A0000000A8800902 1010000000000000000000000000000010x01000100000000000100100000010
  128 A000000088A00901 101000000000000000000000000000001000100010x000000000100100000001
  256 A000000088802902 10100000000000000000000000000000100010001000000000x0100100000010
  512 A000000088800942 101000000000000000000000000000001000100010000000000010010x000010
 1024 A000000088808902 101000000000000000000000000000001000100010000000x000100100000010
 2048 A000000088804902 1010000000000000000000000000000010001000100000000x00100100000010
 4096 A000000088801902 101000000000000000000000000000001000100010000000000x100100000010
 8192 A000000088080903 10100000000000000000000000000000100010000000x0000000100100000011
16384 A00000008A800902 10100000000000000000000000000000100010x0100000000000100100000010
32768 A000000088800B02 101000000000000000000000000000001000100010000000000010x100000010

Start counting after the loooong row of zeroes:
Bit  UsualValue  WhatFor
  1  1           ?
  2  0           ?
  3  Bit         64
  4  0           ?
  5  1           ?
  6  0           ?
  7  Bit         16384
  8  Bit         1
  9  1/0         ?
 10  Bit         2
 11  Bit         128
 12  Bit         16
 13  Bit         8192
 14  Bit         4
 15  Bit         8
 16  0           ?
 17  Bit         1024
 18  Bit         2048
 19  Bit         256
 20  Bit         4096
 21  1           ?
 22  0           ?
 23  Bit         32768
 24  1           ?
 25  0           ?
 26  Bit         512
 27  0           ?
 28  Bit         32
 29  0           1 = card is ignored by reader?
 30  0           1 = card is ignored by reader?
 31  1/0         ?
 32  Checksum: if count of ones in previous 31 bits are even, cs is 1, otherwise 0?

There's a lot of bits I don't know what they do or what they're for, and I'm really not sure how checksum is calculated, but every time the reader did nothing on modified UID, the last bit was the opposite. So far counting ones, even number is 1 and odd number is 0, has worked.

Doing this on Excel and Calculator was alright for a while, but fed up and made a few ugly PHP scripts to ease things. Again, I can't guarantee these work for you or every time. I tried to comment and write the code in a way that it will be easily understood and ported to other languages.

Here's one for generating UIDs. Takes a card number as an argument. Run like php -f indala.generate.php 666.

<?php
// Take card number as an argument, check it's a number, etc. and
// throw an error w/ example if argument isn't valid
$cardnumber = false;
$n = $argv[1];
if((is_numeric($n)) && ($n+0)>0) $cardnumber = $n+0;
if($cardnumber==false) die("You need to give a card number as an argument, e.g.:\n " . $argv[0] . " 666\n");

// This is the "zero card" which gets its bits flipped
$zerocard = '1010000000000000000000000000000010001000100000000000100100000010';
// Throw the zero card to another variable, you may debug later what this script does
$card = $zerocard;
// Proxmark gives values starting 101 and looots of zeroes, 31th bit
// is the first one after that
$offset = 31;

// Now it goes ugly and fast because I handle bit "flipping" in strings
// Convert the card number to binary and reverse it
$cardnumberbin = strrev(decbin($cardnumber));
// Start checking the binary card number from the least meaning bit
for($i = 0; $i <= strlen($cardnumberbin); $i ++) {
  // Take a bit...
  $bit = substr($cardnumberbin, $i, 1);
  // ...and if it's one, change it
  if($bit=='1') {
    // Which bit of the reversed binary card number it is and flip the right bit
    // So fancy
    if($i==0)  $card[$offset + 8]  = '1'; // Bit for 1
    if($i==1)  $card[$offset + 10] = '1'; // Bit for 2
    if($i==2)  $card[$offset + 14] = '1'; // Bit for 4
    if($i==3)  $card[$offset + 15] = '1'; // Bit for 8
    if($i==4)  $card[$offset + 12] = '1'; // Bit for 16
    if($i==5)  $card[$offset + 28] = '1'; // Bit for 32
    if($i==6)  $card[$offset + 3]  = '1'; // Bit for 64
    if($i==7)  $card[$offset + 11] = '1'; // Bit for 128
    if($i==8)  $card[$offset + 19] = '1'; // Bit for 256
    if($i==9)  $card[$offset + 26] = '1'; // Bit for 512
    if($i==10) $card[$offset + 17] = '1'; // Bit for 1024
    if($i==11) $card[$offset + 18] = '1'; // Bit for 2048
    if($i==12) $card[$offset + 20] = '1'; // Bit for 4096
    if($i==13) $card[$offset + 13] = '1'; // Bit for 8192
    if($i==14) $card[$offset + 7]  = '1'; // Bit for 16384
    if($i==15) $card[$offset + 23] = '1'; // Bit for 32768
    }
  }
// Try to guess the checksum: if number of ones after $offset is even, checksum is 1,
// otherwise it's 0?
$c = substr_count($card, '1', $offset);
if($c % 2==0) $card[63] = '1';
// Now $card has the needed bits, now converting to something Proxmark understands
// Preparing hex variable so that strings can be appended to it
$hex = '';
// There's 64 bits, or should be, so process them in 8 bits at a time
for($i = 0; $i < strlen($card); $i = $i + 8) {
  // Take 8 bits from $card
  $bits = substr($card, $i, 8);
  // Turn the bits first into decimal number, then to hex string
  $d = dechex(bindec($bits));
  // Append the hex string to $hex, adding leading zero if $hex is too short
  $hex .= (strlen($d)==1 ? '0' : '') . $d;
  }
// All done, print the used card number and the hex for Proxmark
print "Wanted card number: $cardnumber\n";
print "Hex for Proxmark3:  $hex\n";

And another for decoding UIDs or long bit rows back into human readable card number. Run like php -f indala.decode.php A000000088080903.

<?php
// Take card data in hex or bits from command line argument
$bits = $argv[1];
// Every hex values start with a, right...? We need to convert it to bits
if(strtolower(substr($bits, 0, 1))=='a') {
  // Prepare a temporary variable where bits converted from hex will be put
  $binary = '';
  // One octet at a time
  for($i = 0; $i < strlen($bits); $i = $i + 2) {
    // Grab an octet, convert hex->decimal->binary (I know), add leading zeros
    // so that you get eight bits, not less, and append the converted octet to result
    $bit = substr($bits, $i, 2);
    $bit = decbin(hexdec($bit));
    $bit = str_repeat('0', 8 - strlen($bit)) . $bit;
    $binary .= $bit;
    }
  // Result to the variable to be checked
  $bits = $binary;
  }
// Start from zero, add values if bits are on
$cardnumber = 0;
// That's the spot where loooong row of zeros end and first one is seen
$offset = 31;
// If the bit at [position] is one, add value to cardnumber
if($bits[$offset + 8]=='1') $cardnumber += 1; // Bit for 1
if($bits[$offset + 10]=='1') $cardnumber += 2; // Bit for 2
if($bits[$offset + 14]=='1') $cardnumber += 4; // Bit for 4
if($bits[$offset + 15]=='1') $cardnumber += 8; // Bit for 8
if($bits[$offset + 12]=='1') $cardnumber += 16; // Bit for 16
if($bits[$offset + 28]=='1') $cardnumber += 32; // Bit for 32
if($bits[$offset + 3]=='1') $cardnumber += 64; // Bit for 64
if($bits[$offset + 11]=='1') $cardnumber += 128; // Bit for 128
if($bits[$offset + 19]=='1') $cardnumber += 256; // Bit for 256
if($bits[$offset + 26]=='1') $cardnumber += 512; // Bit for 512
if($bits[$offset + 17]=='1') $cardnumber += 1024; // Bit for 1024
if($bits[$offset + 18]=='1') $cardnumber += 2048; // Bit for 2048
if($bits[$offset + 20]=='1') $cardnumber += 4096; // Bit for 4096
if($bits[$offset + 13]=='1') $cardnumber += 8192; // Bit for 8192
if($bits[$offset + 7]=='1') $cardnumber += 16384; // Bit for 16384
if($bits[$offset + 23]=='1') $cardnumber += 32768; // Bit for 32768
// Fancy part ends and the card number is there
print "The card number is $cardnumber.\n";

The original ID card boxes does have facility code printed on them, but if configure the USB reader to output FAC too, it's zero on every card. So... our facility code is actually zero? It makes me wonder if there's overlapping number ranges in the neighborhood.

Anyway, I'll leave these here and thank for the great tool. smile

Offline

#2 2020-01-09 08:07:34

Charlie
Contributor
Registered: 2017-01-27
Posts: 129

Re: Generating UIDs of Indala/Hedengren cards

Can I contact you by email?

Offline

#3 2020-01-09 19:32:55

iceman
Administrator
Registered: 2013-04-25
Posts: 9,497
Website

Re: Generating UIDs of Indala/Hedengren cards

@randomdude42    I implemented your stuff into the client.  Works like a charm.

[con] pm3 --> lf indala clone -c 123
[=] Heden2L Cardnumber 123 ; RawID A0 00 00 00 A9 D2 09 13
[=] Preparing to clone Indala 64bit tag with RawID
[+] Blk | Data
[+] ----+------------
[+]  00 | 00081040
[+]  01 | A0000000
[+]  02 | A9D20913
[+] Success writing to tag

[con] pm3 --> lf search
[=] NOTE: some demods output possible binary
[=] if it finds something that looks like a tag
[=] False Positives ARE possible
[=]
[=] Checking for known tags...
[=]
[+] Indala Found - bitlength 64, Raw a0000000a9d20913

[+] Possible de-scramble patterns
[+]     Printed     | __1050__ [0x41A]
[+]     Internal ID | 701630739
[+]     Heden-2L    | 123
[+] Fmt 26 bit  FC 2 , CSN 15493 , checksum 11

[+] Valid Indala ID found!

Offline

#4 2020-01-12 18:43:14

randomdude42
Contributor
Registered: 2019-12-31
Posts: 3

Re: Generating UIDs of Indala/Hedengren cards

@Charlie I enabled form email on my profile. Not sure if I can help, but throw me a message.

@iceman Yes, indeed, pulled the latest code on Github to confirm. Thank you!

Offline

Board footer

Powered by FluxBB