Merge pull request #181 from betawave/relay-mitm-enhancement
basic Man-in-the-Middle extension to the Relay-Card
This commit is contained in:
@@ -24,6 +24,7 @@ vpicccards_PYTHON = virtualsmartcard/cards/__init__.py \
|
||||
virtualsmartcard/cards/ePass.py \
|
||||
virtualsmartcard/cards/nPA.py \
|
||||
virtualsmartcard/cards/Relay.py \
|
||||
virtualsmartcard/cards/RelayMiddleman.py \
|
||||
virtualsmartcard/cards/cryptoflex.py
|
||||
|
||||
do_subst = $(SED) \
|
||||
|
||||
@@ -66,6 +66,10 @@ relay.add_argument("--reader",
|
||||
type=int,
|
||||
default=0,
|
||||
help="number of the reader containing the card to be relayed (default: %(default)s)")
|
||||
relay.add_argument("--mitm",
|
||||
action="store",
|
||||
type=str,
|
||||
help="relative path to a file containing a Man-in-the-Middle class that is supposed to be used with the relay")
|
||||
|
||||
npa = parser.add_argument_group('Emulation of German identity card (`--type=nPA`)')
|
||||
npa.add_argument("--ef-cardaccess",
|
||||
@@ -153,7 +157,7 @@ else:
|
||||
hostname = args.hostname
|
||||
|
||||
vicc = VirtualICC(args.datasetfile, args.type, hostname, args.port,
|
||||
readernum=args.reader, ef_cardaccess=ef_cardaccess_data,
|
||||
readernum=args.reader, mitmPath=args.mitm, ef_cardaccess=ef_cardaccess_data,
|
||||
ef_cardsecurity=ef_cardsecurity_data, ca_key=ca_key_data, cvca=cvca,
|
||||
disable_checks=args.disable_ta_checks, esign_ca_cert=esign_ca_cert,
|
||||
esign_cert=esign_cert, logginglevel=logginglevel)
|
||||
|
||||
@@ -370,6 +370,30 @@ class Iso7816OS(SmartcardOS):
|
||||
self.mf.current = self.mf
|
||||
|
||||
|
||||
def loadMitMFromPath(path: str):
|
||||
from importlib import import_module
|
||||
from pathlib import Path
|
||||
def onNth(tup,ind,func):
|
||||
start = tup[0:ind] + (func(tup[ind]),)
|
||||
return start if ind + 1 == 0 else start + tup[ind+1:]
|
||||
|
||||
def pathToModuleName(path):
|
||||
return ".".join(onNth(Path(path).parts,-1,lambda fName : str(Path(fName).stem)))
|
||||
|
||||
mitmModule = import_module(pathToModuleName(path))
|
||||
|
||||
# Sanity Checks
|
||||
if not getattr(mitmModule,"get_MitM",None):
|
||||
raise ValueError("The provided module does not contain a 'get_MitM' method.")
|
||||
mitm = mitmModule.get_MitM()
|
||||
if not getattr(mitm,"handleInPDU",None):
|
||||
raise ValueError("The produced MitM has no 'handleInPDU' method.")
|
||||
if not getattr(mitm,"handleOutPDU",None):
|
||||
raise ValueError("The produced MitM has no 'handleOutPDU' method.")
|
||||
|
||||
return mitm
|
||||
|
||||
|
||||
# sizeof(int) taken from asizof-package {{{
|
||||
_Csizeof_short = len(struct.pack('h', 0))
|
||||
# }}}
|
||||
@@ -393,7 +417,7 @@ class VirtualICC(object):
|
||||
"""
|
||||
|
||||
def __init__(self, datasetfile, card_type, host, port,
|
||||
readernum=None, ef_cardsecurity=None, ef_cardaccess=None,
|
||||
readernum=None, mitmPath=None, ef_cardsecurity=None, ef_cardaccess=None,
|
||||
ca_key=None, cvca=None, disable_checks=False, esign_key=None,
|
||||
esign_ca_cert=None, esign_cert=None,
|
||||
logginglevel=logging.INFO):
|
||||
@@ -429,7 +453,9 @@ class VirtualICC(object):
|
||||
self.os = CryptoflexOS(MF, SAM)
|
||||
elif card_type == "relay":
|
||||
from virtualsmartcard.cards.Relay import RelayOS
|
||||
self.os = RelayOS(readernum)
|
||||
from virtualsmartcard.cards.RelayMiddleman import RelayMiddleman
|
||||
mitm = loadMitMFromPath(mitmPath) if mitmPath else RelayMiddleman()
|
||||
self.os = RelayOS(readernum,mitm=mitm)
|
||||
elif card_type == "handler_test":
|
||||
from virtualsmartcard.cards.HandlerTest import HandlerTestOS
|
||||
self.os = HandlerTestOS()
|
||||
|
||||
@@ -22,6 +22,7 @@ import logging
|
||||
import smartcard
|
||||
import sys
|
||||
from virtualsmartcard.VirtualSmartcard import SmartcardOS
|
||||
from virtualsmartcard.cards.RelayMiddleman import RelayMiddleman
|
||||
|
||||
|
||||
class RelayOS(SmartcardOS):
|
||||
@@ -31,7 +32,7 @@ class RelayOS(SmartcardOS):
|
||||
an actual smart card reader and sends the responses back to the vpcd.
|
||||
This class can be used to implement relay or MitM attacks.
|
||||
"""
|
||||
def __init__(self, readernum):
|
||||
def __init__(self, readernum, mitm=RelayMiddleman()):
|
||||
"""
|
||||
Initialize the connection to the (physical) smart card via a given
|
||||
reader
|
||||
@@ -57,6 +58,8 @@ class RelayOS(SmartcardOS):
|
||||
|
||||
logging.info("Connected to card in '%s'", self.reader)
|
||||
|
||||
self.mitm = mitm
|
||||
|
||||
atexit.register(self.cleanup)
|
||||
|
||||
def cleanup(self):
|
||||
@@ -119,6 +122,8 @@ class RelayOS(SmartcardOS):
|
||||
else:
|
||||
apdu = list(msg)
|
||||
|
||||
apdu = self.mitm.handleInPDU(apdu)
|
||||
|
||||
try:
|
||||
rapdu, sw1, sw2 = self.session.sendCommandAPDU(apdu)
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
@@ -133,5 +138,7 @@ class RelayOS(SmartcardOS):
|
||||
else:
|
||||
rapdu = rapdu + [sw1, sw2]
|
||||
|
||||
rapdu = self.mitm.handleOutPDU(rapdu)
|
||||
|
||||
# return the response APDU as string
|
||||
return "".join(map(chr, rapdu))
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
class RelayMiddleman(object):
|
||||
"""
|
||||
The RelayMiddleman class serves as a base from which a user might derive
|
||||
their own relay middle man class. This base class implements the simplest
|
||||
Man-in-the-Middle: the NoOp.
|
||||
"""
|
||||
|
||||
def handleInPDU(self, inPDU: bytes):
|
||||
"""
|
||||
This method is called on each PDU that is fed into the realy (vdpu -> vicc).
|
||||
It may be overwritten to modify the packages send from the terminal to the
|
||||
real smart card.
|
||||
"""
|
||||
return inPDU
|
||||
|
||||
def handleOutPDU(self, outPDU: bytes):
|
||||
"""
|
||||
This method is called on each PDU that is produced by the relay (vicc -> vdpu).
|
||||
It may be overwritten to modify the packages send from the real smart card to the
|
||||
terminal.
|
||||
"""
|
||||
return outPDU
|
||||
Reference in New Issue
Block a user