Home RACTF 2022
Post
Cancel

RACTF 2022

crypto/Lightning Seeds

Description: You won’t be able to break this, we used a randomizer!

python file
output file

Python code

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
import random

with open('flag.txt', 'r') as f:
    flag = f.read()

seed = random.randint(0,999)
random.seed(seed)

encrypted = ''.join(f'{(ord(c) ^ random.randint(0,255)):02x}' for c in flag)

with open('out.txt', 'w') as f:
    f.write(encrypted)

Output file

4fcbac835550403f13c4cc337d8d8da48351921dfb7cd47d33857432c2ee665d821227

On seeing the description and the python script one can easily guess that the challenge has something to do with Pseudo Random Number Generator. The python random function is seeded with a random integer between 0 and 999, which is a very short range. So the numbers can be easily bruteforced. The challenge may have many approaches. In this writeup we’ll look into the brute force approach

  1. We’ll look into how the flag is encrypted
1
2
# encrypt.py
encrypted = ''.join(f'{(ord(c) ^ random.randint(0,255)):02x}' for c in flag)
  • Each character in flag is iterated.
  • The unicode value of each character is xor’ed with a random number within range of 0 and 255.
  • It is then converted to hex and joined to form the encrypted string. The 02x mentions 2 digits and hexadecimal form
  1. Decrypt using brute force approach
  • To brute force we’ll have to do 3 steps
    1. Split the encrypted text into groups of 2 and convert them to int.
    2. Since we the flag format ie.DOCTF{.*}, we should xor the first value of the encrypted text that was converted to int with all values from 0 to 255.
    3. Next we need to find which seed value was used that gives the random int value of the previous step.
  • The following code is for step 1 and step 2
    1
    2
    3
    4
    5
    6
    7
    8
    
    def find_flag():
      with open('out.txt.1', 'r') as f:
          encrypted = f.read()
          encrypted_split = [(encrypted[i:i+2]) for i in range(0, len(encrypted), 2)] # to split in groups of 2
          integer_converted = [int(x,16) for x in encrypted_split] # to convert to integers
          for i in range(0,256):
              if(chr(integer_converted[0] ^ i) == 'D'): # to find the first random number of the sequence
                  print(f"seed: {i}")
    
  • The following code is for step 3
    1
    2
    3
    4
    5
    
    def find_seed_sequence():
      for i in range(0,1000):
          random.seed(i)
          if(random.randint(0,255) == 11): # 11 was got from previous step
              print(f"seed found! {i}") # finds all possible seeds that generates 11 as the first number
    
  • We get 4 possible seeds
    1
    2
    3
    4
    
    seed found! 209
    seed found! 231
    seed found! 378
    seed found! 876
    
  • The next step is to use the seeds to decrypt the text in out.txt
    1
    2
    3
    4
    5
    6
    7
    8
    
    def find_flag_with_seed():
      with open('out.txt.1', 'r') as f:
          encrypted = f.read()
          encrypted_split = [(encrypted[i:i+2]) for i in range(0, len(encrypted), 2)]
          for i in [209, 231, 378, 876]:
              random.seed(i) # create a PRNG with custom seed
              decrypted_flag = ''.join(f"{chr(int(x,16) ^ random.randint(0,255))}" for x in encrypted_split)
              print(decrypted_flag)
    
  • Gives the following output
    1
    2
    3
    4
    
    D>wûkaok▒¯uxõµ6Û4'UÚ&þ£n
    Dn #9ÞëúcZàC°ñ3ÙªøubÔn^ÞGýØ▒
    D_ck±2X±`ª.ç*«éºL¡¬Àh
    DOCTF{n0t_4s_r4nd0m_4s_y0u_th1nk!}
    

Flag: DOCTF{n0t_4s_r4nd0m_4s_y0u_th1nk!}

This post is licensed under CC BY 4.0 by the author.
Trending Tags