# Write Up BearcatCTF 2025

---
## web
### 1. global-redirect

Truy cập trang:

Đọc src:

Thêm endpoint:
> http://chal.bearcatctf.io:39724/0078f62f00305b73de6ccace8f9fc1f68a8f1dcec865d33fcacbaf255ddefaa7

> Flag: BCCTF{T1ck3t_t0_0wn3rsh1p!}
---
## rev
### 1. Say Cheese

Đề cho:
```py=
import base64
def encoder(input_str, key):
encoded_chars = []
for i in range(len(input_str)):
key_c = key[i % len(key)]
encoded_c = chr((ord(input_str[i]) + ord(key_c)) % 256)
encoded_chars.append(encoded_c)
encoded_str = ''.join(encoded_chars)
return base64.b64encode(encoded_str.encode()).decode()
def main():
print(""" _--"-.
.-" "-.
|""--.. '-.
| ""--.. '-.
|.-. .-". ""--..".
|'./ -_' .-. |
| .-. '.-' .-'
'--.. '.' .- -.
""--.. '_' :
""--.. |
""-' """)
ciphertext = "wpbCi8KIwpfCh8OPwph5wqnCosK6woTCqcKnwq13wrfCh8KzwqnCpMKKccOJwrh8wqTCl3LDgcKHw4U="
key = "THECAT"
inp = input("Enter your cat: ")
encoded_flag = encoder(inp, key)
if ciphertext == encoded_flag:
print("YAY you found the cat!")
else:
print("Not so easy cheesy huh?")
if __name__ == "__main__":
main()
```
Script solve:
```py=
import base64
def decoder(encoded_str, key):
decoded_str = base64.b64decode(encoded_str).decode()
decoded_chars = []
key_len = len(key)
for i in range(len(decoded_str)):
key_c = key[i % key_len]
decoded_c = chr((ord(decoded_str[i]) - ord(key_c)) % 256)
decoded_chars.append(decoded_c)
return ''.join(decoded_chars)
def main():
ciphertext = "wpbCi8KIwpfCh8OPwph5wqnCosK6woTCqcKnwq13wrfCh8KzwqnCpMKKccOJwrh8wqTCl3LDgcKHw4U="
key = "THECAT"
decoded_flag = decoder(ciphertext, key)
print("Decoded flag:", decoded_flag)
if __name__ == "__main__":
main()
```
> Flag: BCCTF{D1d_y0U_h4v3_a_G0ud4_T1m3}
---
## osint
### 1. Been Touring the Arctic

Bài cho file `.kml`, bỏ vào GG earth, có được hình tượng con bearcat, tra 1 hồi là có:
> Flag: BCCTF{Arctictis_binturong}
---
### 2. Building Breakers

Bài cho ảnh:

Dùng lens có ngay:
Swiss National Museum (Schweizerisches Landesmuseum) ở Zurich, Thụy Sĩ.
> Flag: BCCTF{Swiss_National_Museum}
---
## Misc
### 1. What you see

Bài cho 1 ảnh, dùng aperi có được pass:

Dùng pass `ctf`, có được:

> Flag: BCCTF{w34k_s4uc3_4_u}
---
### 2. Ohio Against The World

Tools stego gif:
> https://github.com/dtmsecurity/gift
```bash=
python3 gift-cli.py --source TheEarth.gif recover TheTruth.txt
strings TheTruth.txt | grep bcc
bcctf{sWaG_L!k3_0h1O}Vj
```
> Flag: bcctf{sWaG_L!k3_0h1O}
---
## crypto
### 1. Seeing Triple

Dùng cyberchef là ra:

> Flag: BCCTF{Its_Jus#_H3x}
---
### 2. sqRSA

Bài cho:
```py=
from Crypto.Util.number import getPrime, bytes_to_long
from Crypto.Util.Padding import pad
with open('flag.txt','rb') as fil:
FLAG = fil.read()
e = 2
p = getPrime(512)
q = getPrime(512)
n = p*q
print(f'{e = }')
print(f'{p = }')
print(f'{q = }')
print(f'{n = }')
m = bytes_to_long(pad(FLAG,100))
c = pow(m, e, n)
print(f'{c = }')
phi = (p-1)*(q-1)
d = pow(e,-1,phi) # It always errors here?!!?!
print(f'{phi = }')
print(f'{d = }')
pt = pow(c,d,n)
assert pt == m
```
```bash=
e = 2
p = 8946541176074654913817717054410771331419218032593785296134838490312525894218240553305396599307555077734655624876704161811830296918000348456470769765921767
q = 8932929811422923151480388874853984777290071075825590049173830382535883452482114410463430296988680318519251836647527145507992221700683938654669731212502879
n = 79918824380879984230214478212107859789970760434299554608805294793725784734356035450441094355662829397276452220713697299759466084320223642049726452788651518853937184518959195516619507938497758925978032369947277889352888108330331269331130005097469138112607532759174992940835608455793923500626923539208576267193
c = 17349894155329354363328734000800652637346887108866919240446747423455120556394923514564284438906649577094462846372316919957176356395706169922421515974398971844608693078173465906525109301576180786133798467234128571459625488335621909834995712400917418963473920470534646258784866422718709370743346105151573384808
Traceback (most recent call last):
File "sqRSA.py", line 23, in <module>
d = pow(e,-1,phi) # It always errors here?!!?!
ValueError: base is not invertible for the given modulus
```
Script solve:
```py=
from Crypto.Util.number import long_to_bytes
from Crypto.Util.Padding import unpad
# Given values from the challenge
e = 2
p = 8946541176074654913817717054410771331419218032593785296134838490312525894218240553305396599307555077734655624876704161811830296918000348456470769765921767
q = 8932929811422923151480388874853984777290071075825590049173830382535883452482114410463430296988680318519251836647527145507992221700683938654669731212502879
n = 79918824380879984230214478212107859789970760434299554608805294793725784734356035450441094355662829397276452220713697299759466084320223642049726452788651518853937184518959195516619507938497758925978032369947277889352888108330331269331130005097469138112607532759174992940835608455793923500626923539208576267193
c = 17349894155329354363328734000800652637346887108866919240446747423455120556394923514564284438906649577094462846372316919957176356395706169922421515974398971844608693078173465906525109301576180786133798467234128571459625488335621909834995712400917418963473920470534646258784866422718709370743346105151573384808
# Since e = 2, we can try taking the square root modulo n
def sqrt_mod_n(c, p, q, n):
# Find sqrt mod p
mp = pow(c, (p + 1) // 4, p) if p % 4 == 3 else None
# Find sqrt mod q
mq = pow(c, (q + 1) // 4, q) if q % 4 == 3 else None
if mp is None or mq is None:
raise ValueError("p or q is not congruent to 3 mod 4")
# Use Chinese Remainder Theorem to combine
coef1 = pow(q, -1, p) * q
coef2 = pow(p, -1, q) * p
# Calculate all possible roots
r1 = (mp * coef1 + mq * coef2) % n
r2 = (mp * coef1 - mq * coef2) % n
r3 = n - r1
r4 = n - r2
return [r1, r2, r3, r4]
try:
# Get all possible square roots
possible_messages = sqrt_mod_n(c, p, q, n)
# Try each possible message
for m in possible_messages:
try:
# Convert to bytes and try to unpad
potential_flag = unpad(long_to_bytes(m), 100)
# If it successfully unpads and looks like a flag, print it
if b'flag' in potential_flag.lower() or b'{' in potential_flag:
print(f"Found flag: {potential_flag.decode()}")
except Exception as e:
continue
except Exception as e:
print(f"Error: {e}")
```
> Flag: BCCTF{Don7_b3_4_squArE_ac6c54f792c90a69b8}
---
## forensics
### 1. Lost City

Mở file `.pcap`, follow tcp stream là thấy được 1 ảnh jpg, lưu về có flag:


> Flag: bcctf{fTp5_n0T_so_53cReT}
---
### 2. Around the World

Bài cho file ảnh nhưng thực ra là file gif, thay header là xong:

> Flag: bcctf{C1F_M4g1c_Rev34l}
---