FMS(Fluhrer, Mantin and Shamir))attack是一种针对RC4的攻击,这种攻击方式在2001年的论文Weaknesses in the Key Scheduling Algorithm of RC4中被提到。该攻击利用RC4中的密钥调度算法(KSA)的弱点来从加密消息中重构出密钥。FMS攻击在一些网络工具(例如AirSnort、weplab和aircrack)中得到了普及应用,这些工具使用该攻击来恢复受WEP保护的无线网络的密钥。
攻击描述
在WEP中,不仅仅有用户所输入的key,同时也有设置好的iv(initialization vector),WEP会将它俩拼在一起作为RC4的密钥调度算法中所输入的key,即inputKey = iv + key,这样可以防止key复用所导致的一些问题,但是这也并不是安全的。
defdo_typing(): echo("iv > ") iv = unhex(input()) iflen(iv) != 3: echo("ERROR: The length of IV must be 3.\n") return
prng = PRNG() prng.ksa(iv + KEY) plaintext = b"The Big Monkey is now typing...:" + os.urandom(128) ciphertext = b'' for i inrange(len(plaintext)): ciphertext += bytes([plaintext[i] ^ prng.prng()]) echo("Tac, tac, tac... The monkey is typing: " + enhex(ciphertext) + "\n")
defdo_pay_flag(): echo("iv > ") iv = unhex(input()) iflen(iv) != 3: echo("The length of IV must be 3.\n") return echo("input > ") ciphertext = unhex(input())
prng = PRNG() prng.ksa(iv + KEY) plaintext = b'' for i inrange(len(ciphertext)): plaintext += bytes([ciphertext[i] ^ prng.prng()])
ifb"There is nothing either good or bad, but thinking makes it so."in plaintext: echo("The infinite monkey theorem is true. " + FLAG + "\n")
echo("Done.\n")
defmain(): echo("""\ __,__ .--. .-" "-. .--. / .. \/ .-. .-. \/ .. \\ | | '| / Y \ |' | | | \ \ \ 0 | 0 / / / | \ '- ,\.-"`` ``"-./, -' / T H E I N F I N I T E M O N K E Y G A M E `'-' /_ ^ ^ _\ '-'` .--'| \._ _ _./ |'--. /` \ \.-. / / `\\ 0> Start typing / '._/ |-' _.' \\ / ; /--~' | \\ 1> Pay flag / .'\|.-\--. \ \\ / .'-. /.-.;\ |\|'~'-.|\ \\ 2> Exit \ `-./`|_\_/ ` `\\'. \\ '. ; ___) '.`; / '-.,_ ; ___) \/ / \ ``'------'\ \ ` / '. \ '. | ;/_ jgs ___> '. \_ _ _/ , '--. .' '. .-~~~~~-. / |--'`~~-. \\ // / .---'/ .-~~-._/ / / /---..__.' / ((_(_/ / / (_(_(_(---.__ .' | | _ `~~` | | \\'. \ '....' | '.,___.' \n""") whileTrue: print("key:",KEY.hex()) echo("\nInput your choice> ") choice = input() ifnot choice.strip(): continue choice = int(choice)
#!/usr/bin/env python from pwn import * from tqdm import tqdm from Crypto.Util.number import * #context.log_level = "debug"
plain = b"There is nothing either good or bad, but thinking makes it so." key_length = 9
# Helper function, which swaps two values in the box. defswapValueByIndex(box, i, j): temp = box[i] box[i] = box[j] box[j] = temp
# Initialize S-box. definitSBox(box): iflen(box) == 0: for i inrange(256): box.append(i) else: for i inrange(256): box[i] = i
# Key schedule Algorithm (KSA) for key whose value is in unicode. defksa(key, box): j = 0 for i inrange(256): j = (j + box[i] + ord(key[i % len(key)])) % 256 swapValueByIndex(box, i, j)
classPRNG: def__init__(self): self.state = [i for i inrange(256)] self.i = 0 self.j = 0
def__swap_state(self, a, b): self.state[a], self.state[b] = self.state[b], self.state[a]
defcmd(idx): r.sendlineafter("Input your choice> ",str(idx))
deftyping(iv): cmd(0) r.sendlineafter("iv > ",iv) r.recvuntil("Tac, tac, tac... The monkey is typing: ") result = int(r.recvuntil("\n",drop = True),16) result = long_to_bytes(result) return result
defgetflag(iv,cipher): cmd(1) r.sendlineafter("iv > ",iv) r.sendlineafter("input > ",cipher) r.recvuntil("The infinite monkey theorem is true. ") flag = r.recvuntil("\n",drop = True, timeout = 2) return flag
r = process(argv=["python3", "chall.py"]) #r = remote("8.131.246.36",12180) iv = [0,255,0] rows = [] for A in tqdm(range(key_length)): iv[0] = A + 3 for thirdByte inrange(256): iv[2] = thirdByte cipherByte = typing(bytes(iv).hex())[0] rows.append([iv[0],iv[1],iv[2],cipherByte])
box = [] plainKnown = "54" key = [None] * 3 for A inrange(key_length): prob = [0] * 256 for row in rows: key[0] = int(row[0]) key[1] = int(row[1]) key[2] = int(row[2]) j = 0 initSBox(box) for i inrange(A + 3): j = (j + box[i] + key[i]) % 256 swapValueByIndex(box, i, j) if i == 1: original0 = box[0] original1 = box[1] i = A + 3 z = box[1] if z + box[z] == A + 3: if (original0 != box[0] or original1 != box[1]): continue keyStreamByte = int(row[3]) ^ int(plainKnown, 16) keyByte = (keyStreamByte - j - box[i]) % 256 prob[keyByte] += 1 higherPossibility = prob.index(max(prob)) key.append(higherPossibility)
userInput = key[3:] result = [format(key, 'x') for key in userInput] rawkey = ''.join(result) rawkey = rawkey.ljust(18,"0") print(rawkey) iv = "777777" key = long_to_bytes(int(iv + rawkey,16)) prng = PRNG() prng.ksa(key) cipher = b'' for i inrange(len(plain)): cipher += bytes([plain[i] ^ prng.prng()]) cipher = cipher.hex() flag = getflag(iv,cipher) print(flag) r.close()