swiss hacking challenge 2024 - farm-life
Difficulty: easy
Category: crypto
Author: Roxy
Susan from HR decided that to improve team spirit in the office, they would all go volunteer on a farm. This caused terrible drama with Veronica, who claimed to have had the idea first. Marcel chimed in that he hated stinky farms and, like probably everybody else, would not want to join a trip where he would only ruin his brand new white sneakers. Rumor has it that after weeks of bickering, Veronica booby-trapped the office kitchen and caused Susan to trip…
Files
We are given an otp_public.py
file:
#!/usr/bin/env python3
import secrets
FLAG = "FAKE_FLAG"
def encrypt(key, plaintext):
return ''.join(str(int(a) ^ int(b)) for a, b in zip(key, plaintext))
def main():
# keygen
key = format(secrets.randbits(365), 'b')
print("Welcome to the CryptoFarm!")
while True:
command = input('Would you like to encrypt a message yourself [1], get the flag [2], or exit [3] \n>').strip()
try:
if command == "1":
data = input('Enter the binary string you want to encrypt \n>')
print("Ciphertext = ", encrypt(key, data))
key = format(secrets.randbits(365), 'b')
elif command == "2":
print("Flag = ", encrypt(key, format(int.from_bytes(FLAG.encode(), 'big'), 'b')))
elif command == "3":
print("Exiting...")
break
else:
print("Please enter a valid input")
except Exception:
print("Something went wrong.")
if __name__ == "__main__":
main()
Exploitation
As we can see, the key
variable gets overwritten after we encrypt a message. This means we’ll have to get the flag first.
An OTP / One-Time-Pad is secure as long as the key isn’t used for multiple plaintexts. This is exactly what happens here though.
We can encrypt a ton of zeroes and then xor it with the flag using the provided encrypt
function:
Welcome to the CryptoFarm!
Would you like to encrypt a message yourself [1], get the flag [2], or exit [3]
>2
Flag = 010010011010101110011100011000101110111100110011011010001001001011010000010101010000100000011010111010001100101110010000000110000111110110010101110010001000110100110100110011011111011011011011100000011100011100011110111110110010111100110101111000001001110011111100111001111110110000100001001111001101001
Would you like to encrypt a message yourself [1], get the flag [2], or exit [3]
>1
Enter the binary string you want to encrypt
>00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Ciphertext = 10101111011110110101101000000110100011110101011100000000011001000100111010001101110000001010010001000100000000010100110011000110101000010101011101110110000111011111011000000101010010000101100100111111010100011001010001001001100100011011111100101010010011100011011000101101001111101111111111101100001010010010110010110101100100110111010010011111110000001110100100000
Would you like to encrypt a message yourself [1], get the flag [2], or exit [3]
a = "010010011010101110011100011000101110111100110011011010001001001011010000010101010000100000011010111010001100101110010000000110000111110110010101110010001000110100110100110011011111011011011011100000011100011100011110111110110010111100110101111000001001110011111100111001111110110000100001001111001101001"
b = "10101111011110110101101000000110100011110101011100000000011001000100111010001101110000001010010001000100000000010100110011000110101000010101011101110110000111011111011000000101010010000101100100111111010100011001010001001001100100011011111100101010010011100011011000101101001111101111111111101100001010010010110010110101100100110111010010011111110000001110100100000"
c = encrypt(a,b)
from Crypto.Util.number import long_to_bytes
long_to_bytes(int(c,2))
As using zeroes for the XORed ciphertext means, we just get the key, we can just get the flag:
Flag
Conclusion
Took me some attempts to get this right, maybe a proper solve script next time would be better.