For this challenge we were presented with a short python programme (below) which was designed to produce a one-time passcode based on an account number and the current time. We were asked what the passcode would be for a given account and a time a few weeks in the past.
Firstly, we had to add the required date and time rather than real time by modifying either line 20 or 24 to generate the correct value of BigNumber. The only remaining problem was to disable the IntegrityChecker by commenting out line 5 and the integrity check itself starting at line 63.
The key message to take from this exercise is that software running on client machines can never be trusted. This was a trivial example, but even signed compiled software can be manipulated by a clever adversary, particularly where it has to run on generic computers over which you have no control.
[codesyntax lang=”python” lines=”normal” title=”Passcode Generator”]
# Secure One-Time PassCode Generator, written by Budget Coding Ltd for BigBank PLC import datetime import base64 import IntegrityChecker def getAccntNumber(): AccntNumber = [] while len(AccntNumber) != 8 or not AccntNumber.isdigit(): AccntNumber = (raw_input('Please enter your 8-digit Account Number: ')) if len(AccntNumber) != 8 or not AccntNumber.isdigit(): print("Not a valid account number. Please Try again...") print("") return AccntNumber def getPassCode(AccntNumber): # Get Current Time TimeNow = str(datetime.datetime.now().strftime('%Y,%m,%d,%H,%M')) # Extract numbers and combine together [Year,Month,Day,Hour,Minute] = TimeNow.split(',') BigNumber = ((int(Year) * int(Month) * int(Day)) + (int(Hour) * int(Minute))) ** 2 # Create two sets of interleaving numbers and combine to get another Big Number NumberSetA = int(str(BigNumber)[0::2]) NumberSetB = int(str(BigNumber)[1::2]) NewBigNumber = NumberSetA * NumberSetB # Do some clever maths if BigNumber > NewBigNumber: SmallerNumber = BigNumber - NewBigNumber elif NewBigNumber > BigNumber: SmallerNumber = NewBigNumber - BigNumber else: SmallerNumber = BigNumber / 2 # Do some maths with the Account Number EvenBiggerNumber = SmallerNumber * int(AccntNumber) # Pad number to fixed size PaddedEvenBiggerNumber = str(EvenBiggerNumber).ljust(20,"0") PassCode = [] # Take chunks from padded number and average to get passcode for N in range(0,4): Chunk = PaddedEvenBiggerNumber[N::5] SplitChunk = Chunk[0:3] y = 0 for x in SplitChunk: y = y + int(x) PassCode.append(int(y/4)) return PassCode ###### Core Code ###### # Check file hasn't been tampered with if IntegrityChecker.CheckIntegrityOfFile() is False: print("This File Has Been Tampered With!! Exiting...") exit() PassWord = raw_input("Please Enter your Password: ") PassWordHash = base64.b64encode(PassWord) CorrectHash = "aG9yc2ViYXR0ZXJ5c3RhcGxl" if PassWordHash == CorrectHash: print("Your PassCode is: %s") % getPassCode(getAccntNumber()) print("") print("This PassCode will expire in less than a minute. Please re-run to get a new code if it has expired.") else: print "Password Incorrect..."
[/codesyntax]