Local fork of Henryk Ploetz' smardcard shell
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cyberflex-shell/brutefid.py

201 lines
7.6 KiB

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import utils, cards, TLV_utils, sys, binascii, time, traceback, smartcard, readers
OPTIONS = "m:x:dD"
LONG_OPTIONS = ["min-fid", "max-fid", "with-dirs", "dump-contents"]
STATUS_INTERVAL = 10
SPINNER = ['/','-','\\','|']
results_dir = {}
results_file = {}
contents_file = {}
top_level = None
start_time = time.time()
loop = 0
min_fid = 0
max_fid = 0xffff
with_dirs = False
dump_contents = False
def dump(data):
print "Dump following (%i bytes)" % (len(data))
print utils.hexdump(data)
try:
print "Trying TLV parse:"
print TLV_utils.decode(data, tags=card.TLV_OBJECTS, context = card.DEFAULT_CONTEXT)
print "TLV parsed successfully"
except (SystemExit, KeyboardInterrupt):
raise
except:
print "TLV error"
pass
if __name__ == "__main__":
c = readers.CommandLineArgumentHelper()
(options, arguments) = c.getopt(sys.argv[1:], OPTIONS, LONG_OPTIONS)
for option, value in options:
if option in ("-m","--min-fid"):
min_fid = int(value, 16)
elif option in ("-x","--max_fid"):
max_fid = int(value, 16)
elif option in ("-d","--with-dirs"):
with_dirs = not with_dirs
elif option in ("-D", "--dump-contents"):
dump_contents = not dump_contents
if len(arguments) > 0:
top_level = ("".join( ["".join(e.split()) for e in arguments] )).split("/")
top_level = [binascii.unhexlify(e) for e in top_level]
print "Reading /%s from %04X to %04X%s" % (
top_level is not None and "/".join("%r" % e for e in top_level) or "",
min_fid,
max_fid,
with_dirs and " (DFs treated separately)" or "",
)
card_object = c.connect()
card = cards.new_card_object(card_object)
cards.generic_card.DEBUG = False
print "Using %s" % card.DRIVER_NAME
card.change_dir()
if top_level is not None:
for e in top_level:
if len(e) == 2:
card.change_dir(e)
else:
card.select_application(e)
root_node = cards.iso_7816_4_card.iso_node(generic_description="Brute Force Results Tree")
#objective = (0x2f00, 0x5015) ## Test cases on an OpenSC formatted PKCS#15 card
#objective = range(0xffff+1)
#objective = range(0x3fff+1) + range(0x7000,0x7fff+1) + range(0xc000,0xd4ff+1) + range(0xd600+1,0xd7ff+1) + range(0xdc00+1,0xffff+1)
objective = range(min_fid, max_fid+1)
try:
for fid in objective:
data = chr(fid >> 8) + chr(fid & 0xff)
if loop % STATUS_INTERVAL == 0:
elapsed = time.time() - start_time
status = "(elapsed: %i:%02i:%02i" % (elapsed / 3600, (elapsed / 60) % 60, elapsed % 60)
try:
eta = (elapsed / loop) * (len(objective) - loop)
status = status + ", left: %i:%02i:%02i" % (eta / 3600, (eta / 60) % 60, eta % 60)
except: pass
if with_dirs: status = status + ", dirs: %2i" % len(results_dir)
status = status + ", files: %2i)" % len(results_file)
loop = loop + 1
if with_dirs:
try:
result = card.change_dir(data)
except smartcard.Exceptions.CardConnectionException:
time.sleep(1)
result = card.change_dir(data)
if card.check_sw(result.sw):
results_dir[fid] = result
card.change_dir()
if top_level is not None:
for e in top_level:
if len(e) == 2:
card.change_dir(e)
else:
card.select_application(e)
print >>sys.stderr, "\rDir %04X -> %02X%02X %s " % (fid, result.sw1, result.sw2, status),
try:
result = card.open_file(data)
except smartcard.Exceptions.CardConnectionException:
time.sleep(1)
result = card.open_file(data)
if card.check_sw(result.sw):
results_file[fid] = result
if dump_contents:
contents, sw = card.read_binary_file()
contents_result = [sw]
if sw == '\x69\x81': # Command incompatible with file structure, retry read_record
# FIXME this logic for reading records is not correct
print >>sys.stderr, "\rFile %04X -> %02X%02X %s Reading records... " % (fid, result.sw1, result.sw2, status),
records = {}
for i in range(256):
if i%STATUS_INTERVAL == 0:
print >>sys.stderr, "\rFile %04X -> %02X%02X %s Reading records... %s" % (fid, result.sw1, result.sw2, status,
SPINNER[ (i/STATUS_INTERVAL) % len(SPINNER) ],
),
records[i] = card.read_record(i, 4, 0)
contents_result.append(records)
elif sw == '\x69\x82': # Security status not satisfied
pass
elif sw == '\x90\x00': # Command execution successful
contents_result.append(contents)
elif len(contents) > 0: # Something was returned, assume successful execution
contents_result.append(contents)
contents_file[fid] = contents_result
print >>sys.stderr, "\rFile %04X -> %02X%02X %s " % (fid, result.sw1, result.sw2, status),
except (SystemExit, KeyboardInterrupt):
raise
except:
traceback.print_exc()
print >>sys.stderr
print "="*80
print "Results:"
for fid, result in sorted(results_dir.items()):
if results_file.has_key(fid):
continue
print "-"*80
print "Dir\t%04X" % fid
if len(result.data) > 0:
print utils.hexdump(result.data)
try: print TLV_utils.decode(result.data,tags=card.TLV_OBJECTS)
except: print "Exception during TLV parse"
for fid, result in sorted(results_file.items()):
print "-"*80
print "File\t%04X" % fid
if len(result.data) > 0:
print utils.hexdump(result.data)
try: print TLV_utils.decode(result.data,tags=card.TLV_OBJECTS)
except: print "Exception during TLV parse"
if contents_file.has_key( fid ):
contents_result = contents_file[fid]
if contents_result[0] == '\x69\x81':
print "Record-oriented file"
elif contents_result[0] == '\x69\x82':
print "Can't read file"
elif len(contents_result) > 1:
if contents_result[0] == '\x90\x00':
print "Transparent file"
else:
print "Strange file (%02X%02X)" % (ord(contents_result[0][0]), ord(contents_result[0][1]))
if len(contents_result) > 1:
if isinstance(contents_result[1], str):
dump(contents_result[1])
else:
for index, data in contents_result[1].items():
if len(data) > 0:
print "Record %i:" % index
dump(data)
print
print
print "<"*40 + ">"*40
root_node.print_node()