ScriptCTF 2025 Write-up
This write-up contains solutions of few challenges from ScriptCTF 2025, where I (solo) bagged 403rd place out of 1767 teams from all over the world. It contained challenges suitable for beginners to seasoned hackers. Do not miss the last challenge, I loved it the most.
Misc
Rules
Just read the rules and you will have a link to prizes, the flag is on top right corner scriptCTF{600D_1ucK_5011D3r1}
Div
You are provided with a chall.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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...')
You have to find a way to enter a number that is large enough to divide the secret and result is 0.
Solution: Enter the input as Infinity 
This will give you the flag scriptCTF{70_1nf1n17y_4nd_b3y0nd_f6c842098579}
Crypto
RSA-1
solve.py
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
67
68
from gmpy2 import isqrt, iroot
# Given values
n1 = 156503881374173899106040027210320626006530930815116631795516553916547375688556673985142242828597628615920973708595994675661662789752600109906259326160805121029243681236938272723595463141696217880136400102526509149966767717309801293569923237158596968679754520209177602882862180528522927242280121868961697240587
c1 = 77845730447898247683281609913423107803974192483879771538601656664815266655476695261695401337124553851404038028413156487834500306455909128563474382527072827288203275942719998719612346322196694263967769165807133288612193509523277795556658877046100866328789163922952483990512216199556692553605487824176112568965
n2 = 81176790394812943895417667822424503891538103661290067749746811244149927293880771403600643202454602366489650358459283710738177024118857784526124643798095463427793912529729517724613501628957072457149015941596656959113353794192041220905793823162933257702459236541137457227898063370534472564804125139395000655909
c2 = 40787486105407063933087059717827107329565540104154871338902977389136976706405321232356479461501507502072366720712449240185342528262578445532244098369654742284814175079411915848114327880144883620517336793165329893295685773515696260299308407612535992098605156822281687718904414533480149775329948085800726089284
n3 = 140612513823906625290578950857303904693579488575072876654320011261621692347864140784716666929156719735696270348892475443744858844360080415632704363751274666498790051438616664967359811895773995052063222050631573888071188619609300034534118393135291537302821893141204544943440866238800133993600817014789308510399
c3 = 100744134973371882529524399965586539315832009564780881084353677824875367744381226140488591354751113977457961062275480984708865578896869353244823264759044617432862876208706282555040444253921290103354489356742706959370396360754029015494871561563778937571686573716714202098622688982817598258563381656498389039630
e = 3
# Step 1: Verify GCDs to ensure pairwise coprimality
from math import gcd
gcd12 = gcd(n1, n2)
gcd23 = gcd(n2, n3)
gcd13 = gcd(n1, n3)
print(f"GCD(n1, n2) = {gcd12}")
print(f"GCD(n2, n3) = {gcd23}")
print(f"GCD(n1, n3) = {gcd13}")
# Assuming GCDs are 1 (pairwise coprime), proceed with CRT
# Note: If GCDs are not 1, we’d need to factor the moduli, but let’s try CRT first
# Step 2: Compute m^3 using CRT
# We use a simplified CRT implementation for three moduli
def crt(a, n):
# a = [c1, c2, c3], n = [n1, n2, n3]
N = n[0] * n[1] * n[2]
result = 0
for i in range(3):
Ni = N // n[i]
# Compute modular inverse of Ni mod n[i]
y = pow(Ni, -1, n[i]) # Using Fermat’s little theorem or extended GCD
result += a[i] * Ni * y
return result % N, N
# Compute m^3
m3, N = crt([c1, c2, c3], [n1, n2, n3])
print(f"m^3 mod N = {m3}")
# Step 3: Check if m^3 < N
if m3 < N:
print("m^3 is exact (no modular reduction needed)")
else:
print("m^3 >= N, attack may fail or need adjustment")
exit()
# Step 4: Compute the integer cube root
m, exact = iroot(m3, 3)
if exact:
print(f"Plaintext m = {m}")
else:
print("Cube root is not exact, attack failed")
exit()
# Step 5: Convert m to bytes and check if it’s a meaningful message
try:
message = m.to_bytes((m.bit_length() + 7) // 8, byteorder='big')
print(f"Message (bytes): {message}")
# Try decoding as ASCII
print(f"Message (ASCII): {message.decode('ascii')}")
except UnicodeDecodeError:
print("Message is not valid ASCII, outputting raw bytes")
print(f"Raw bytes: {message.hex()}")
Used AI to write the above code…
flag scriptCTF{y0u_f0und_mr_yu's_s3cr3t_m3g_12a4e4}
Secure-server
Attachment: files.zip
You are provided with a capture.pcap file and a server.py file
server.py
1
2
3
4
5
6
7
8
9
10
import os
from pwn import xor
print("With the Secure Server, sharing secrets is safer than ever!")
enc = bytes.fromhex(input("Enter the secret, XORed by your key (in hex): ").strip())
key = os.urandom(32)
enc2 = xor(enc,key).hex()
print(f"Double encrypted secret (in hex): {enc2}")
dec = bytes.fromhex(input("XOR the above with your key again (in hex): ").strip())
secret = xor(dec,key)
print("Secret received!", (secret).hex())
We observe the following from the packet capture file: Secret XORed with User Key (in hex):
1
151e71ce4addf692d5bac83bb87911a20c39b71da3fa5e7ff05a2b2b0a83ba03
Double encrypted secret (in hex):
1
e1930164280e44386b389f7e3bc02b707188ea70d9617e3ced989f15d8a10d70
XOR the above with your key again (in hex):
1
87ee02c312a7f1fef8f92f75f1e60ba122df321925e8132068b0871ff303960e
solve.py
1
2
3
4
5
6
7
8
9
10
11
from pwn import xor
# Replace these with the actual hex strings from the conversation
enc = bytes.fromhex("151e71ce4addf692d5bac83bb87911a20c39b71da3fa5e7ff05a2b2b0a83ba03") # First input: secret XOR user's key
enc2 = bytes.fromhex("e1930164280e44386b389f7e3bc02b707188ea70d9617e3ced989f15d8a10d70") # Output: double-encrypted secret
dec = bytes.fromhex("87ee02c312a7f1fef8f92f75f1e60ba122df321925e8132068b0871ff303960e") # Second input: enc2 XOR user's key
# Compute secret = (dec XOR enc) XOR enc2
secret = xor(xor(dec, enc), enc2)
print("Secret (ASCII):", secret.decode())
Explanation: XORing enc and dec cancels out user’s key, leaving us secret and enc2. When we XOR enc2 with secret and enc2 , we are left with just secret i.e flag. tip: look comments closely to understand how we are eliminating.
OSINT
Insider
Go to Noobmaster’s profile on discord.
Insider 2
Go to Noobmaster’s profile on discord. On his discord profile, scroll below you get link to login of 2026 ScriptCTF and link to his GitHub account.
on his GitHub, check his last commit you get creds.txt
use the credentials to login. and boom! 
Insider 3
Go to latest commits of GitHub account and you will get the flag
Web
Renderer
We know that the cookie is at the following path
Grab the cookie
Only if we access the /developer directory with the correct cookie, we can get the flag.
Craft the magic request
1
curl -X GET http://play.scriptsorcerers.xyz:10289/developer -H "Cookie: developer_secret_cookie=400ba24a6f9e51dbbadd555e067c963ed1fe2430aa49a26de7ebe2a2019a5ed9"
Forensics
pdf challenge.pdf
perform binwalk and extract the flag.txt. 
diskchal
you get a file stick.img Perform binwalk and extracted a file flag.txt.
1
2
3
binwalk -e stick.img
cd _stick.img.extracted
cat flag.txt
Just Some Avocado This was my favorite challenge avocado.jpg
You are provided with a .jpg file, perform binwalk to extract it’s contents. Three files are provided
188F7.zip- password protectedjustsomezip.zip- emptystaticnoise.wav- empty
Bruteforce 188F7.zip with rockyou.txt using fcrackzip to get the password
1
fcrackzip -u -D -p rockyou.txt 188F7.zip
1
impassive3428
You will be provided with 2 files
justsomezip.zip- password protectedstaticnoise.wav- normal audio file
To find the password of justsomezip.zip Open Sonic Visualiser
1
sonic-visualiser staticnoise.wav
Select Layer => Add Spectogram
Adjust to see the text clearly 
1
d41v3ron
use the above password to extract the contents of the zip file.
We get flag.txt
1
scriptCTF{1_l0ve_d41_v3r0n}
That’s a wrap. Meet you in future write-ups. Hope you learnt new things.











