Skip to content
{{ message }}

Instantly share code, notes, and snippets.

# shirriff/mathcrack.py

Last active Feb 17, 2019
Rapidly crack Xerox Alto disk passwords using a mathematical formula that reverses the password hash
 # Crack Xerox Alto disk passwords using math. import sys def findPasswd(passvec): # a and b are the salt values a = (passvec << 16) + passvec b = (passvec << 16) + passvec if a == 0 or b == 0: print 'No password' return if passvec == 0: print 'Password (disabled):' else: print 'Password:' # c is the known hashed password # The password characters are concatenated into x and y. # Since we don't know the password, brute force the 65536 possibilities for x c = (passvec << 48) | (passvec << 32) | (passvec << 16) | passvec; for x in range(0, 65536): # Solve the password equation for y t = (x * x) & 0xffffffff t = (t * a) & 0xffffffffffffffff t ^= 0xffffffff00000000 t += 1 btimesy = (c - t) & 0xffffffffffffffff y = btimesy / b # If quotient didn't work, try next x if (y * b) & 0xffffffffffffffff != btimesy: continue # Concat sequence is first char into x, next two into y, one into x, etc. # Try different password lengths to find which one works for i in range(1, 15): password = '' x1 = x y1 = y for j in range(i, 0, -1): if (j % 3) == 1: char = chr((x1 >> 9) & 0x7f) x1 = (x1 << 7) & 0xffff else: char = chr((y1 >> 25) & 0x7f) y1 = (y1 << 7) & 0xffffffff password = char + password if x1 == 0 and y1 == 0 and '\0' not in password: print i, password # Get word at the word offset in the disk file def getWord(wordOffset): return ord(diskContents[2 * wordOffset]) + ord(diskContents[2 * wordOffset + 1]) * 256 def getSector(addr): # Convert address (sector/cylinder/head) into a linear address sec = addr >> 12 cyl = (addr >> 3) & 0x1ff h = 1 if (addr & 0x4) else 0 n = sec + (cyl*2 + h) * 12 offset = n*(256 + 10 + 1) header = [getWord(offset + i) for i in range(1, 3)] label = [getWord(offset + i) for i in range(3, 11)] data = [getWord(offset + i) for i in range(11, 267)] return header, label, data, offset diskContents = None # Crack passwords from three Alto disks def main(): global diskContents if len(sys.argv) != 2: sys.exit('Usage: mathcrack filename.dsk') with open(sys.argv, 'rb') as f: diskContents = f.read() header, label, data, offset = getSector(0) nextAddr = label header, label, data, offset = getSector(nextAddr) chars = ''.join(['%s%s' % (chr(word>>8), chr(word&0xff)) for word in data]) off = 0 length = data[off] >> 8 print 'Disk user:', chars[2*off+1:2*off+1+length] off = (1+length+1) / 2 # Move to next string length = data[off] >> 8 print 'Disk name:', chars[2*off+1:2*off+1+length] passvec = data[128:128+9] findPasswd(passvec) def test(): print 'Disk 37' # passvec is the 9-word password vector from sys.boot # passvec must be big-endian passvec = [0xffff, 0xe9d3, 0x0f9a, 0x0da5, 0x53b4, 0xc3f4, 0x382a, 0xd974, 0x5589] findPasswd(passvec) print '\nDisk 47' passvec = [0xffff, 0xcfa7, 0x9f3d, 0x669a, 0xf2bb, 0xf193, 0x6d09, 0x4571, 0xe1d1] findPasswd(passvec) print '\nDisk 72' passvec = [0xffff, 0x8341, 0x772c, 0x249b, 0x1be2, 0xf71f, 0x5b87, 0x9fce, 0x0581] findPasswd(passvec) if __name__ == "__main__": main()

### Cabalist commented Jan 5, 2018

 Very cool.

### bittorf commented Jan 6, 2018

 You made my weekend! 8-)
to join this conversation on GitHub. Already have an account? Sign in to comment