vrijdag 31 mei 2013

getChallengeResponse.sh script

#!/bin/sh
# getChallengeResponse.sh - login to my online banking website using the challenge-reponse mechanism
# Purpose of this script (work in progress) is to further automate online banking.
# More info: http://globalblindspot.blogspot.be/2010/07/getting-emvcap-challengeresponse-to.html
# Author: Tom Van Braeckel 

pin="$1"
challenge="$2"

if [ -z "$pin" -o `expr length "$pin"` -ne 4 -o -z "$challenge" -o `expr length "$challenge"` -ne 8 ]; then
 echo "Usage: $0  "
 echo "Example: $0 3117 12345678"
 exit 1
fi

# Can you guess what this method does ?
bintodec() {
 bin="$1"
 echo "obase=10; ibase=2; $bin" | bc
}

# remove < and " "
compact() {
 while read line; do
  echo "$line" | tr -d '<' | tr -d ' '
 done
}

# args: command to execute on the card
execOnCard() {
 cla="$1"
 ins="$2"
 p1="$3"
 p2="$4"
 le="$5"
 data="$6"
 tosend="${cla}${ins}${p1}${p2}${le}${data}"
 #echo "Sending $tosend" >&2
 echo "$tosend" | scriptor 2>/dev/null | grep -A 10000 "<"
  # does not work:
# echo "$cla $ins $p1 $p2 $le $data" | scriptor 2>/dev/null | grep "<"
}

execOnCardRespond() {
 cla="$1"
 ins="$2"
 p1="$3"
 p2="$4"
 le="$5"
 data="$6"
 result=$(execOnCard $cla $ins $p1 $p2 $le $data) ; echo "result = $result" >&2
 # get length in hex
 length=$(echo "$result" | cut -d ' ' -f 3); #echo "length = $length"
 execOnCard 00 c0 00 00 $length | compact
}

# Can you guess what this method does ?
hextobin() {
 hex="$1"
 echo "ibase=16; obase=2; $hex" | bc
}

# do a read data with the correct length...
readData() {
 p2="$1"
 recordLength=$(execOnCard 80 ca 9f $p2 00 | cut -d ' ' -f 3)
 #echo "recordLength = $recordLength" >&2
 # cut off first bytes (status code, length)
 # cut off last bytes (9000Normalprocessing)
 # for some reason we NEED CLA 80 here, 00 doesn't work...
 execOnCard 80 ca 9f $p2 $recordLength | compact | tail -c +7 | head -c -23
 echo
}

readRecord() {
 p1="$1"
 p2="$2"
 errorWithLength=$(execOnCard 00 b2 $p1 $p2 00)
 #echo "errorWithLength = $errorWithLength"
 recordLength=$(echo "$errorWithLength" | cut -d ' ' -f 3)
 #echo "recordLength = $recordLength"
 execOnCard 00 b2 $p1 $p2 $recordLength | compact
}

readRecords() {
 SFI="$1" # five most significant bits
 recNr="$2" # second byte
 lastRecNr="$3" # third byte
 if [ "$SFI" = "1" ]; then
  p2=0c # (sfi << 3) + 4
 else
  echo "I don't know p2 !"
  sleep 3
 fi
 # READ RECORD(s)
 for i in `seq $recNr $lastRecNr`; do
  readRecord 0$i $p2
 done
}

zeropadfront() {
 targetLength="$1"
# echo "targetLength = $targetLength"
 while read line; do
#  echo "got line $line"
  length=$(expr length "$line")
  while [ $length -lt $targetLength ]; do
   line="0${line}"
   length=$(expr length "$line")
  done
  echo "$line"
 done
}

#################################################################
###################### EXECUTION STARTS HERE ####################
#################################################################

# reset
execOnCard reset

#select file/application
aid=A0000000048002 # securecode aut
#aid=A0000000043060 # maestro (debit)
response=$(execOnCardRespond 00 a4 04 00 07 ${aid})
echo $response

# this is needed, otherwise the commands below fail...
PDOL=$(echo "$response" | grep -o -E "9F38........" | tail -c +7)
echo "PDOL = $PDOL"
# for securecode get a PDOL of "9F3501" (eg "9F38039F3501")
# this is the "Terminal Type" - don't know the value, but I use 00...

# get processing options:
# - Application Interchange Profile (AIP)
# - Application File Locator (AFL)
if [ -z "$PDOL" ]; then
 response=$(execOnCardRespond 80 a8 00 00 02 8300); echo $response
 # eg: ...94080801030110010201
 AIP=3800 # this means "initiate", "data auth", RFU
 AFLs="08010301 10010201"
else
 # PDOL specifies one tag with value of 1 byte, but I don't know which value...
 response=$(execOnCardRespond 80 a8 00 00 03 830100); echo $response
 # 770E82021000940808010100080404009000:Normalprocessing.
 AIP=1000 # this means "initiate"
 AFLs="08010100 08040400"
fi
echo "Found AIP = $AIP and AFLs = $AFLs"

# Read SecureCode records and extract valueable info
cardinfo=$(readRecords 1 1 1)
PAN=$(expr substr "$cardinfo" 9 18)
echo "Application Primary Account Number (PAN) = $PAN"
authinfo=$(readRecords 1 4 4)
bitmap=$(expr substr "$authinfo" 11 22)
echo "Proprietary Authentication Challenge-Reponse Bitmap = $bitmap"

# This works for maestro:
if false; then
 readRecords 1 1 3

 # second group in AFL
 SFI=10 # five most significant bits
 recNr=1 # second byte
 lastRecNr=2 # third byte
 offlineDataRec=1 # fourth byte
 # p2=binary(firstbyte)100 left shift 3 OR 100 ???
 # p2=binary(firstbyte) shift right 3
 # I calculated 84, but it seems to be (13) 14 / (1B) 1C / (23) 24
 # and also 03 04 0B 0C but we found those above
 p2s="14 1C 24"
 # READ RECORD(s)
 for p2 in $p2s; do
  for i in `seq $recNr $lastRecNr`; do
   echo -n "p2 = $p2, recordNr = $i: "
   readRecord 0$i $p2
  done
 done
fi

# get pin try counter length
pinTry=$(readData 17)
echo "pinTry = $pinTry"
if [ "$pinTry" != "02" -a "$pinTry" != "03" ]; then
 echo "WARNING: pinTry < 2 !"
 sleep 15
fi

# get Application Transaction Counter
echo -n "Application Transaction Counter = "
readData 36

# get Last Online ATC Register
echo -n "Last Online ATC Register = "
readData 13

echo -n "Log Entry = "
readData 4D

echo -n "Log Format = "
readData 4F

# submit pin
execOnCard 00 20 00 80 08 24${pin}FFFFFFFFFF

# generate Application RQ Cryptogram
# p1=80=Authorisation Request Cryptogram
countrycode=0056 # OTF mentions 0000, chip&pin uses 0826
currencycode=0978 # OTF mentions 0000, chip&pin uses 0826
date=$(date +"%y%m%d")
CardholderVerificationMethodResults=010002
# 8000000000 = Terminal Verification Codes: Data authentication was not performed (recommended by optimized to fail)
# 00 = transaction type
# 0000 = ICC Dynamic Number
ARQC_response=$(execOnCardRespond 80 AE 80 00 22 000000000000000000000000${countrycode}8000000000${currencycode}${date}00${challenge}0000${CardholderVerificationMethodResults})
echo "ARQC_response = $ARQC_response"
CID=$(expr substr "$ARQC_response" 11 2)
ATC=$(expr substr "$ARQC_response" 19 4)
AC=$(expr substr "$ARQC_response" 29 16)
#IAD=$(expr substr "$ARQC_response" 51 15)
# testing to see if we get the same response as in chip&pin - we do, so this is OK.
# CID=80; ATC=A52D; AC=AD452EF6BA769E4A; IAD=06770A03A48000; bitmap=00001F00000000000FFFFF00000000008000


# generate Application Cryptogram for challenge 12345678
# 5a33 = Authorisation Response Code, generated by terminal or bank (for online stuff)
IAuthData=0000000000000000000000000000000000000000 # Issuer Authentication Data (NOT Issuer Application Data !)
AC_response=$(execOnCardRespond 80 AE 00 00 2e 5a33000000000000000000000000${countrycode}8000000000${currencycode}${date}00${challenge}0000${CardholderVerificationMethodResults}${IAuthData})
echo "AC_response = $AC_response"
#AC_response="$ARQC_response" # Testing which response we need - normally the second one, but let's try this for a laugh
CID=$(expr substr "$AC_response" 11 2)
ATC=$(expr substr "$AC_response" 19 4)
AC=$(expr substr "$AC_response" 29 16)

# extract response
echo "CID=$CID, ATC=$ATC, AC=$AC, IAD=$IAD"

# length of bitmap is used as the target length for the response
bitmap_hex_length=$(expr length "$bitmap")
bitmap_bin_length=$(expr "$bitmap_hex_length" \* 4)
echo bitmap_hex_length=$bitmap_hex_length, bitmap_bin_length=$bitmap_bin_length

# Do logical AND with bitmap
CIDATCAC_bin=$(hextobin "${CID}${ATC}${AC}${IAD}" | zeropadfront "$bitmap_bin_length")
echo "CIDATCAC_bin = $CIDATCAC_bin"
bitmap_bin=$(hextobin "$bitmap" | zeropadfront "$bitmap_bin_length")
echo "  bitmap_bin = $bitmap_bin"

# if a bit of bitmap = 1, then we add the bit from CIDATCAC_bin to filtered_bin
filtered_bin=
for bitpos in `seq 1 $bitmap_bin_length`; do
 bitmap_bit=$(expr substr "$bitmap_bin" "$bitpos" 1)
 if [ $bitmap_bit -eq 1 ]; then
  CIDATCAC_bin_bit=$(expr substr "$CIDATCAC_bin" "$bitpos" 1)
  filtered_bin=${filtered_bin}${CIDATCAC_bin_bit}
 fi
done
echo "filtered_bin = $filtered_bin"
# Note: if ATC>0x26(38) then response = 8 characters
# if ATC=0xFFFF(65536) then response = 12 characters !!! is this correct ?

filtered_dec=$(bintodec $filtered_bin)
echo "RESPONSE = $filtered_dec"

exit


# this is never executed

if false; then
# Make AND of ARQC and Cap bit Filter:
fortis: 77269F2701 00 9F3602 00B7 9F260886F857BEB767E8FB 9F100F 0601560384B0A80701030000000000
kbc:    77269F2701 00 9F3602 0004 9F260831F94BDAB5DF0F38 9F100F 0601560384B0400701030000000000
kbc: 77269F2701 00 9F3602 0005 9F2608B29D6D20BFE004AD 9F100F 0601560384B0400701030000000000
# extracted values
output 00 00B7 86F857BEB767E8FB 0601560384B0A80701030000000000
output 00 0004 31F94BDAB5DF0F38 0601560384B0A80701030000000000
bitmask 00 00FF 000000000003FFFF
filter .. ..04 ...........30F38
binary     0100 110000111100111000
decimal 1249080
fi




Example protocol log:

Collected from a NatWest reader and card performing a respond computation
(ISO 7816, T=0 protocol). Personal details have been redacted.

Command:   00a4040007 (select application)
Proc:      a4
Data:      a0000000048002
Proc:      61
Status:    6112 (more data available)

Command:   00c0000012 (application selected)
Proc:      c0
Data:      6f108407a0000000048002a5055f2d02656e
Proc:      90
Status:    9000 (OK)

Command: 80a8000002 (initiate transaction)
Proc:    a8
Data:    8300
Proc:    61
Status:  6108 (more data available)

Command: 00c0000008 (transaction initiated)
Proc:    c0
Data:    8006100008010100
Proc:    90
Status:  9000 (OK)

Command: 00b2010c00 (get static data length)
Proc:    6c
Status: 6c57 (wrong length)

Command: 00b2010c57 (read static data)
Proc:    b2
Data:    7055
          8e0a 00000000000000000100 (CVM list)
          9f5501 a0 (unknown)
          9f5612 00001f00000000000fffff00000000008000 (bit filter)
          8c15 9f02069f03069f1a0295055f2a029a039c019f3704 (CDOL1)
          8d17 8a029f02069f03069f1a0295055f2a029a039c019f3704 (CDOL2)
Proc:    90
Status: 9000 (OK)

Command: 80ca9f1700 (get PIN try counter length)
Proc:    6c
Status: 6c04 (wrong length)

Command: 80ca9f1704 (get PIN try counter)
Proc:    ca
Data:    9f170103 (3 remaining tries)
Proc:    90
Status:  9000 (OK)

PIN entered: ?

Command: 0020008008 (verify PIN)
Proc:    20
Data:    24xxxxffffffffff
Proc:    90
Status:  9000 (OK)

Challenge entered: 12345678

Command: 80ae80001d (generate ARQC)
Proc:    ae
Data:    0000000000000000000000000000800000000000000000000012345678
Proc:    61
Status:  6114 (more data available)

Command: 00c0000014 (return ARQC)
Proc:    c0
Data:    80 1280 0042b7f9a572da74caff 06770a03a48000
Proc:    90
Status:  9000 (OK)

Command: 80ae00001f (generate AC)
Proc:    ae
Data:    5a330000000000000000000000000000800000000000000000000012345678
Proc:    61
Status:  6114 (more data available)

Command: 00c0000014 (return AAC)
Proc:    c0
Data:    80 1200 00424f1c597723c97d78 06770a03258000
Proc:    90
Status:  9000 (OK)

Response returned: 4822527



Geen opmerkingen:

Een reactie plaatsen