# misc

## Challenges

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2Fc2U2lKYd0Wo5pqaFOOI9%2Fimage.png?alt=media&#x26;token=f697c61d-f465-4b09-a0b6-50b5b8e981da" alt=""><figcaption></figcaption></figure>

### Read The Rules

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FT1nxAplJJF2dcS0ibPe8%2Fimage.png?alt=media&#x26;token=1fafee7f-3d76-4376-8504-e1b061473dee" alt=""><figcaption></figcaption></figure>

> Read the rules. They can be found in the #rules channel in discord, or [here](https://play.scriptsorcerers.xyz/rules). The rules will contain a link, which will ultimately contain the flag.

<details>

<summary>View Hint: Hint 1</summary>

The final page will just display the flag.

</details>

<details>

<summary>View Hint: Hint 2</summary>

If you can't find the flag, you can make a ticket on our discord.

</details>

<details>

<summary>View Hint: Hint 3</summary>

You shouldn't need three hints to solve this challenge, come on!

</details>

* Go to the saide rules page...you should be able to found the links at the very last [line](https://ctf.scriptsorcerers.xyz/prizes)
* <mark style="color:blue;">`scriptCTF{600D_1ucK_5011D3r1}`</mark>

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FO3qRWeHf4xH7uHwXhi65%2Fimage.png?alt=media&#x26;token=00614f5c-d0ab-409e-b814-7288838ddadb" alt=""><figcaption></figcaption></figure>

### Div

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FG0LOuwuDw1OymKoJl1Bh%2Fimage.png?alt=media&#x26;token=d8e59dff-b4aa-4d24-9ee1-765d24686c55" alt=""><figcaption></figcaption></figure>

> I love division
>
> * [chall.py](https://storage.googleapis.com/scriptctf_challenges/Misc/Div/chall.py)

```python
import os
import decimal
decimal.getcontext().prec = 50

secret = int(os.urandom(16).hex(),16)
num = input('Enter a number: ')

if 'e' in num.lower():
    print("Nice try...")
    exit(0)

if len(num) >= 10:
    print('Number too long...')
    exit(0)

fl_num = decimal.Decimal(num)
div = secret / fl_num

if div == 0:
    print(open('flag.txt').read().strip())
else:
    print('Try again...')
```

The answer is **`inf`** because:

`secret / inf = 0`

* "inf" passes both checks (no 'e', length < 10)
* `decimal.Decimal("inf")` creates infinity
* `secret / ∞ = 0` triggers the flag condition
* <mark style="color:blue;">`scriptCTF{70_1nf1n17y_4nd_b3y0nd_00ec1b195af8}`</mark>

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FQRyFjl1RRlxdIc02nHWt%2Fimage.png?alt=media&#x26;token=e7e60c48-1375-4803-99ee-a2f26717ad5d" alt=""><figcaption></figcaption></figure>

### emoji

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FqMOt6nKELAPv5IYbIbtZ%2Fimage.png?alt=media&#x26;token=9ffa26bd-7916-4a88-9bb3-ed2a8973ce30" alt=""><figcaption></figcaption></figure>

> Emojis everywhere! Is it a joke? Or something is hiding behind it.
>
> * [out.txt](https://storage.googleapis.com/scriptctf_challenges/Misc/emoji/out.txt)

```
🁳🁣🁲🁩🁰🁴🁃🁔🁆🁻🀳🁭🀰🁪🀱🁟🀳🁮🁣🀰🁤🀱🁮🁧🁟🀱🁳🁟🁷🀳🀱🁲🁤🁟🀴🁮🁤🁟🁦🁵🁮🀡🀱🁥🀴🀶🁤🁽
```

* This one was quite vauge, so some llm magic and kaboom...we know the type of shennanigen behinds the "emoji"&#x20;
* So the emojis are encoding ASCII text using playing card symbols as a substitution cipher. Each emoji maps to a specific character based on its position in the playing card Unicode block.
* Conversion:
  * `ord(char)` gets the Unicode value of each emoji
  * `- 0x1F030` removes the base playing card offset
  * `+ 48` shifts to ASCII range
  * `chr()` converts back to readable characters
* <mark style="color:blue;">`scriptCTF{3m0j1_3nc0d1ng_1s_w31rd_4nd_fun!1e46d}`</mark>

{% hint style="info" %}
Script
{% endhint %}

{% code overflow="wrap" %}

```python
# emoji_string = "🁳🁣🁲🁩🁰🁴🁃🁔🁆🁻🀳🁭🀰🁪🀱🁟🀳🁮🁣🀰🁤🀱🁮🁧🁟🀱🁳🁟🁷🀳🀱🁲🁤🁟🀴🁮🁤🁟🁦🁵🁮🀡🀱🁥🀴🀶🁤🁽"
with open('emoji.txt', 'r') as file:
    emoji_string = file.read()

flag = ''.join(chr(ord(char) - 0x1F030 + 48) for char in emoji_string)
print(flag)
```

{% endcode %}

### Enchant

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FrVMBpAsz28nAwxFi9xzP%2Fimage.png?alt=media&#x26;token=c90b78b4-98e5-425b-bdb8-2e336c579a54" alt=""><figcaption></figcaption></figure>

> I was playing minecraft, and found this strange enchantment on the enchantment table. Can you figure out what it is? Wrap the flag in scriptCTF{}
>
> * [enc.txt](https://storage.googleapis.com/scriptctf-wave2-randomchars1337/Misc/Enchant/enc.txt)

```
ᒲ╎リᒷᓵ∷ᔑ⎓ℸ ̣ ╎ᓭ⎓⚍リ
```

* tbh, I did a quick paste into Google to see what it is, and I got Galatic Alphabet.

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2Fv5jVoLRfAO0aNUM7K0ie%2Fimage.png?alt=media&#x26;token=423226ac-3ace-44f4-82cf-974718598007" alt=""><figcaption></figcaption></figure>

{% embed url="<https://lingojam.com/StandardGalacticAlphabet>" %}

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FCO5qaN6h155UoVeOgfv9%2Fimage.png?alt=media&#x26;token=6b6a67df-d946-42b3-a30d-f7478ecfb3e1" alt=""><figcaption></figcaption></figure>

* <mark style="color:blue;">`scriptCTF{Minecraftisfun}`</mark>

### Div 2

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FTfipZEaCikSW70NTCpFR%2Fimage.png?alt=media&#x26;token=23ef2d1b-5a2d-4734-b20b-048be9310ef1" alt=""><figcaption></figcaption></figure>

> Some might call this a programming challenge...
>
> * [chall.py](https://storage.googleapis.com/scriptctf-wave2-randomchars1337/Misc/Div%202/chall.py)

```python
import secrets
import decimal
decimal.getcontext().prec = 50
secret =  secrets.randbelow(1 << 127) + (1 << 127) # Choose a 128 bit number

for _ in range(1000):
    print("[1] Provide a number\n[2] Guess the secret number")
    choice = int(input("Choice: "))
    if choice == 1:
        num = input('Enter a number: ')
        fl_num = decimal.Decimal(num)
        assert int(fl_num).bit_length() == secret.bit_length()
        div = secret / fl_num
        print(int(div))
    if choice == 2:
        guess = int(input("Enter secret number: "))
        if guess == secret:
            print(open('flag.txt').read().strip())
        else:
            print("Incorrect!")
        exit(0)
```

What the program does is generate a secret 128-bit number and allows us to

1. Provide a number and get <mark style="color:$danger;">`int(secret / our_number)`</mark>
2. Guess the secret number

The vulnerability is at line&#x20;

* ```python
  div = secret / fl_num
  print(int(div))
  ```
* This gives you <mark style="color:$danger;">`secret // fl_num`</mark> (integer division result), which leaks information about the secret's magnitude relative to your input.
* We also know the secret's range from this line in the challenge:
  * ```python
    secret =  secrets.randbelow(1 << 127) + (1 << 127) # Choose a 128 bit number
    ```
  * That is why we can perform a **search** to narrow down the 128-bit space logarithmically

{% hint style="info" %}
Script
{% endhint %}

```python
from pwn import *

def solve():
    p = process(['python3', 'chall.py'])
    # p = remote('play.scriptsorcerers.xyz', 10311)

    # Binary search for the secret
    # Secret is 128-bit: between 2^127 and 2^128-1

    low = 1 << 127
    high = (1 << 128) - 1

    while low <= high:
        mid = (low + high) // 2
        print(f"Trying mid = {mid}")

        # Query: what is secret // mid ?
        p.sendlineafter(b'Choice: ', b'1')
        p.sendlineafter(b'Enter a number: ', str(mid).encode())

        quotient = int(p.recvline().strip())

        if quotient == 0:
            # secret < mid
            high = mid - 1
        elif quotient == 1:
            # secret >= mid and secret < 2 * mid
            # Check if secret >= mid + 1
            if mid + 1 <= high:
                p.sendlineafter(b'Choice: ', b'1')
                p.sendlineafter(b'Enter a number: ', str(mid + 1).encode())
                quotient2 = int(p.recvline().strip())

                if quotient2 == 0:
                    # secret < mid + 1, so secret == mid
                    secret = mid
                    break
                else:
                    # secret >= mid + 1
                    low = mid + 1
            else:
                secret = mid
                break
        else:
            # quotient >= 2, so secret >= 2 * mid
            low = 2 * mid

    # Guess the secret
    p.sendlineafter(b'Choice: ', b'2')
    p.sendlineafter(b'Enter secret number: ', str(secret).encode())

    result = p.recvline().strip().decode()
    print(f"Result: {result}")
    p.close()

solve()
```

````python
```python
❯ python solve.py
[+] Starting local process '/home/x/miniconda3/envs/ctfs/bin/python3': pid 1176860
Trying mid = 255211775190703847597530955573826158591
Trying mid = 297747071055821155530452781502797185023
Trying mid = 276479423123262501563991868538311671807
Trying mid = 287113247089541828547222325020554428415
...
Trying mid = 281308022660211790137507177938664385631
Trying mid = 281308022660211790137507177938664385647
Trying mid = 281308022660211790137507177938664385639
Trying mid = 281308022660211790137507177938664385643
Trying mid = 281308022660211790137507177938664385641
Result: scriptCTF{b1n4ry_s34rch_u51ng_d1v1s10n?!!_5ad3d0d2dee7}
[*] Stopped process '/home/x/miniconda3/envs/ctfs/bin/python3' (pid 1176860)
````

<mark style="color:blue;">`scriptCTF{b1n4ry_s34rch_u51ng_d1v1s10n?!!_5ad3d0d2dee7}`</mark>

### Subtract&#x20;

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2F43DNg9KdaAHLkN3WTUdF%2Fimage.png?alt=media&#x26;token=a5ebc396-bb62-49b4-b1fc-dc6dc5fb3311" alt=""><figcaption></figcaption></figure>

> The image size is 500x500. You might want to remove some stuff... Note: Some may call it guessy!
>
> * [coords.zip](https://storage.googleapis.com/scriptctf_challenges/Misc/Subtract/coords.zip)

```bash
❯ unzip -l coords.zip
Archive:  coords.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
  2645453  2025-07-12 09:06   coordinates.txt
---------                     -------
  2645453                     1 file
```

* The description said it...the coords is to form an 500x500 image, and we have to remove the noise.
  * Upon closer inspection, many coordinates appear multiple times in the file.

When we count how many times each coordinate appears:

* Most pixels appear an **even number of times** (typically twice)
* A smaller subset appears an **odd number of times** (typically once)
* By keeping only odd-parity pixels, the noise cancels out and the hidden message emerges

{% hint style="info" %}
Script
{% endhint %}

```python
import re
import numpy as np
from PIL import Image
from collections import Counter

def solve():
    # Read coordinates
    with open("coordinates.txt", 'r') as f:
        content = f.read()

    # Extract all (x,y) pairs
    pairs = re.findall(r'\((\d+),\s*(\d+)\)', content)
    coords = [(int(x), int(y)) for x, y in pairs]

    # Count occurrences of each coordinate
    counter = Counter(coords)

    # Create image: only plot coordinates with ODD occurrences
    img = np.zeros((500, 500), dtype=np.uint8)

    for (x, y), count in counter.items():
        if count % 2 == 1:  # Keep odd parity only
            if 0 <= x < 500 and 0 <= y < 500:
                img[y, x] = 255

    # Find content bounds and crop
    white_pixels = np.where(img == 255)
    if len(white_pixels[0]) > 0:
        min_y, max_y = white_pixels[0].min(), white_pixels[0].max()
        min_x, max_x = white_pixels[1].min(), white_pixels[1].max()

        # Add padding
        padding = 10
        min_y = max(0, min_y - padding)
        max_y = min(499, max_y + padding)
        min_x = max(0, min_x - padding)
        max_x = min(499, max_x + padding)

        # Crop and save
        cropped = img[min_y:max_y+1, min_x:max_x+1]
        Image.fromarray(cropped).save('flag.png')
    else:
        Image.fromarray(img).save('flag.png')

solve()
```

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FHwHPU9geH06fDuwnGy2G%2Fimage.png?alt=media&#x26;token=42e7d532-e0eb-44b6-97c9-14b7f017892e" alt=""><figcaption></figcaption></figure>

* What really tripped me up was the character that looked like a `6`. I must have tried it at least 10 different ways (which was all wrong and tanked my accuracy), thinking there was some hidden trick to remove the “noise.”&#x20;
* Turns out, it was just plain leet speak (1337) where `6` should actually be read as `5`. I don’t know if this is the intended way to deduce the solution, but it’s the best explanation I have.

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FUmMLPCN6WSpg5StNIs1m%2Fimage.png?alt=media&#x26;token=eb9682de-fcbc-460e-85bd-ec524d94a098" alt="" width="563"><figcaption></figcaption></figure>

* <mark style="color:blue;">`scriptCTF{5ub7r4c7_7h3_n01s3}`</mark>

### Modulo

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2Fb3eEkeJl4mqb5a6q55WG%2Fimage.png?alt=media&#x26;token=19a9b761-fdaf-456d-b478-bfdbe337281f" alt=""><figcaption></figcaption></figure>

> Modulo is so cool!
>
> * [jail.py](https://storage.googleapis.com/scriptctf-wave2-randomchars1337/Misc/Modulo/jail.py)
> * [Dockerfile](https://storage.googleapis.com/scriptctf-wave2-randomchars1337/Misc/Modulo/Dockerfile)

tbd.
