> For the complete documentation index, see [llms.txt](https://ravins-organization.gitbook.io/ctf-writeups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ravins-organization.gitbook.io/ctf-writeups/2024/gryphons-ctf-2024/re/random-encoder-3.md).

# Random Encoder 3

Oh. My. Goodness.

We are given the following script to reverse

```python
import random as r
r.seed("can_you_solve_this???_1234567890!@#$%^&*()qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM")

flag = "GCTF24{FLAG_REMOVED}"

encoded = ""
for i in flag:
    a = i
    for x in range(r.randint(1, 10)):
        case = r.randint(1, 10)
        if case == 1:
            a = a.swapcase() if r.randint(1, 2) == 1 else a
        elif case == 2:
            a = chr(ord(a) + r.randint(10, 20))
        elif case == 3:
            a = chr(ord(a) - r.randint(10, 20))
        elif case == 4:
            a = chr(ord(a) * r.randint(1, 3))
        elif case == 5:
            a = chr(ord(a) * r.randint(1, 2) - r.randint(25, 50))
        elif case == 6:
            a = chr(ord(a) + r.randint(1, 2))
        elif case == 7:
            a = chr(ord(a) + r.randint(25, 50))
        elif case == 8:
            a = chr(ord(a) + r.randint(200, 300))
        elif case == 9:
            a = chr(ord(a) + r.randint(-10, 10))
        elif case == 10:
            None
    encoded += a
print(encoded) # Flag is ϕż=¦ý<R8dĳՊ¼{ĳɁċkËIdΤŃƠnD͇෗^Ių̔JOʐƠĽ̰ŲfªŮƅ
```

First, lets try to understand this script.

#### Key Components

* Process Each Character of the flag
* Apply a Random Number of Transformations

  ```python
  for x in range(r.randint(1, 10)):
      case = r.randint(1, 10)
  ```
* Perform Transformations Based on case

  ```python
  if case == 1:
      a = a.swapcase() if r.randint(1, 2) == 1 else a
  elif case == 2:
      a = chr(ord(a) + r.randint(10, 20))
  elif case == 3:
      a = chr(ord(a) - r.randint(10, 20))
  ...
  ```
* Depending on the value of case, a specific transformation is applied to a:
  * Case 1: Randomly swaps the case (uppercase ↔ lowercase) with a 50% chance.&#x20;
  * Case 2: Adds a random value (10 to 20) to the ASCII value of the character.&#x20;
  * Case 3: Subtracts a random value (10 to 20) from the ASCII value of the character.&#x20;
  * Case 4: Multiplies the ASCII value by a random factor (1 to 3).&#x20;
  * Case 5: Applies a more complex transformation by multiplying and then subtracting a random value (25 to 50).&#x20;
  * Case 6: Adds a small random value (1 to 2) to the ASCII value.&#x20;
  * Case 7: Adds a large random value (25 to 50) to the ASCII value.&#x20;
  * Case 8: Adds an even larger random value (200 to 300) to the ASCII value.&#x20;
  * Case 9: Adds a small random shift (-10 to 10) to the ASCII value.&#x20;
  * Case 10: Does nothing (None).
* Output

Solve script

```python
import random as r

def reset_random():
    r.seed("can_you_solve_this???_1234567890!@#$%^&*()qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM")

def encode_char(c):
    a = c
    num_ops = r.randint(1, 10)
    for _ in range(num_ops):
        case = r.randint(1, 10)
        code = ord(a)
        try:
            if case == 1:
                if r.randint(1, 2) == 1:
                    a = a.swapcase()
            elif case == 2:
                new_code = code + r.randint(10, 20)
                if 0 <= new_code <= 0x10FFFF:
                    a = chr(new_code)
            elif case == 3:
                new_code = code - r.randint(10, 20)
                if 0 <= new_code <= 0x10FFFF:
                    a = chr(new_code)
            elif case == 4:
                new_code = code * r.randint(1, 3)
                if 0 <= new_code <= 0x10FFFF:
                    a = chr(new_code)
            elif case == 5:
                new_code = code * r.randint(1, 2) - r.randint(25, 50)
                if 0 <= new_code <= 0x10FFFF:
                    a = chr(new_code)
            elif case == 6:
                new_code = code + r.randint(1, 2)
                if 0 <= new_code <= 0x10FFFF:
                    a = chr(new_code)
            elif case == 7:
                new_code = code + r.randint(25, 50)
                if 0 <= new_code <= 0x10FFFF:
                    a = chr(new_code)
            elif case == 8:
                new_code = code + r.randint(200, 300)
                if 0 <= new_code <= 0x10FFFF:
                    a = chr(new_code)
            elif case == 9:
                new_code = code + r.randint(-10, 10)
                if 0 <= new_code <= 0x10FFFF:
                    a = chr(new_code)
        except ValueError:
            return None
        if len(a) != 1:
            return None
    return a


def verify_encoding(known_str, target):
    reset_random()
    result = ""
    for c in known_str:
        encoded = encode_char(c)
        if encoded is None:
            return False
        result += encoded
    return target.startswith(result)

def try_next_char(known_prefix, target_char):
    reset_random()
    for c in known_prefix:
        _ = encode_char(c)
    chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_@!${}."
    for c in "0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ":
        reset_random()
        test_str = known_prefix + c
        if verify_encoding(test_str, encoded):
            return c

    for c in chars:
        reset_random()
        test_str = known_prefix + c
        if verify_encoding(test_str, encoded):
            return c
    
    return None

encoded = "ϕż=¦ý<R8dĳՊ¼{ĳɁċkËIdΤŃƠnD͇෗^Ių̔JOʐƠĽ̰ŲfªŮƅ"
flag = "GCTF24{"

print(f"Starting from known good flag part: {flag}")

while len(flag) < len(encoded) and '}' not in flag:
    next_char = try_next_char(flag, encoded[len(flag)])
    if next_char:
        flag += next_char
        print(f"Found next character: {flag}")
    else:
        test_chars = "1234567890_IS}"
        for test_c in test_chars:
            reset_random()
            test_flag = flag + test_c
            if verify_encoding(test_flag, encoded):
                flag += test_c
                print(f"Found through second attempt: {flag}")
                break
        else:
            flag += '?'
            print(f"Failed to decode position {len(flag)-1}")

    if not verify_encoding(flag, encoded):
        print(f"Verification failed at length {len(flag)}")
        break

print(f"\nFinal decoded flag: {flag}")

reset_random()
final_encoded = ""
for c in flag:
    if c != '?':
        final_encoded += encode_char(c)
print(f"Verification matches: {final_encoded == encoded[:len(final_encoded)]}")
```

Output

```
Starting from known good flag part: GCTF24{
Found next character: GCTF24{w
Found next character: GCTF24{w0
Found next character: GCTF24{w0W
Found next character: GCTF24{w0W_
Found next character: GCTF24{w0W_t
Found next character: GCTF24{w0W_tH
Found next character: GCTF24{w0W_tH@
Found next character: GCTF24{w0W_tH@T
Found next character: GCTF24{w0W_tH@T_
Found next character: GCTF24{w0W_tH@T_c
Found next character: GCTF24{w0W_tH@T_ch
Found next character: GCTF24{w0W_tH@T_cha
Found next character: GCTF24{w0W_tH@T_chal
Found next character: GCTF24{w0W_tH@T_chalL
Found next character: GCTF24{w0W_tH@T_chalL3
Found next character: GCTF24{w0W_tH@T_chalL3N
Found next character: GCTF24{w0W_tH@T_chalL3Ng
Found next character: GCTF24{w0W_tH@T_chalL3Ng3
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_T
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_T3
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_T3d
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_T3d!
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_T3d!0
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_T3d!0U
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_T3d!0Us
Found next character: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_T3d!0Us}

Final decoded flag: GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_T3d!0Us}
Verification matches: True
```

Thus the flag is `GCTF24{w0W_tH@T_chalL3Ng3_W4$_t0O_T3d!0Us}`
