Reused key vulnerability in One-time pad for CTF
Yesterday, I participated in a beginners CTF competition organized by the MonSec. One challenge was to find the flag given two ciphertexts which are said to be encrypted using OTP. However, texts are said to be encrypted using the same key. I couldn’t solve it during the given time. So decided to spend Sunday on this.
I had to read on how OTP get vulnerable if the key is reused. Found an excellent description of that under 1st answer in https://crypto.stackexchange.com/questions/59/taking-advantage-of-one-time-pad-key-reuse It really explains things very clearly. (I used the same images used by the original author.)
Then, I had to figure out how to use that idea to solve the issue. 3rd answer in the same link was so handy in that. So I started with a simple python script. The initial guess was that the key should contain either ‘MONSEC‘ or ‘FLAG‘
c1 = "02036109340314070d131510141c06077a0b646d7f671a0b0d151403120463050b761b3241282f41312d20282f35243935412e2f412c38412524322a352e2d"
c2 = "0b0d0a025b0775001b08166211017f1e711c1d0409711c1d7f1875011777641d64630a24323241233435412420323841352e4133242c242c2324334040405c"
known_word = "FLAG{".encode("utf-8").hex()
test = hex(int(known_word, 16) ^ int(c1[0:len(known_word)], 16))
print(bytes.fromhex(test[2:]).decode("utf-8"))
test = hex(int(known_word, 16) ^ int(c2[0:len(known_word)], 16))
print(bytes.fromhex(test[2:]).decode("utf-8"))
Decoded plain texts seem to make sense. But it was very hard for me to guess the remaining parts. So did another digging and find a gem “cribdrag”. A cool tool that can be used to tackle this sort of problems. So many guesses for several hours and finally able to obtain the key. However, compared steps that are mentioned in some blog posts, what I did was partially cribdrag one of the ciphertexts (instead of c1 ⊕ c2) and use the partially obtained flag on other ciphertexts. I had to do this interchangeably for several iterations.
I believe the attacker needs to know at least some part of the flag or ciphertexts to solve this. Otherwise, I’m not quite sure how can tackle this. Maybe there is a more efficient way of doing this rather than just some guess. Anyway I really enjoyed doing this though it cost me about 8 hours 😁