Skip to content

Commit 278ce64

Browse files
committed
sekai ctf + just ctf
1 parent d7dbf1a commit 278ce64

File tree

15 files changed

+1622
-0
lines changed

15 files changed

+1622
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
created: 2025-08-02T07:59
3+
updated: 2025-08-02T08:01
4+
---
5+
6+
![image.png](https://res.cloudinary.com/kumonochisanaka/image/upload/v1754136059/20250802080058804.png/d8b7482f3bfd07e54a251d6526de44ec.png)
7+
8+
```python
9+
import numpy as np
10+
from scipy.io import wavfile
11+
import matplotlib.pyplot as plt
12+
13+
rate, data = wavfile.read("morse1.wav")
14+
data = np.abs(data)
15+
data = np.array([np.max(data[i:i+1000]) for i in range(0, len(data), 1000)])
16+
data[data < 10000] = 0
17+
data[data > 0] = 1
18+
19+
b_data = ''
20+
21+
c = data[0]
22+
count = 1
23+
24+
for value in data[1:]:
25+
if value == c:
26+
count += 1
27+
else:
28+
rep = round(count/10)
29+
b_data += str(c) * rep
30+
c = value
31+
count = 1
32+
33+
bytes_list = [int(b_data[i:i+8], 2) for i in range(0, len(b_data), 8)]
34+
print(bytes(bytes_list))
35+
```
36+
37+
```flag
38+
justCTF{The-track-name-is-Coldness-and-the-artist-is-The-Wanderer}
39+
```

2025-just-ctf/forensics/index.md

Whitespace-only changes.

2025-just-ctf/index.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
created: 2025-08-02T03:31
3+
updated: 2025-08-02T03:33
4+
title: justCTF 2025
5+
---
6+
7+
::ctf-overview
8+
::

2025-sekai-ctf/index.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
created: 2025-08-16T12:23
3+
points: 957
4+
rank: 61
5+
title: SEKAI CTF 2025
6+
updated: 2025-08-17T20:46
7+
---
8+
9+
Really enjoyed this CTF!
10+
11+
> When would I be able to make fancy themes so unique and cute like SEKAI CTF?
12+
13+
😭 the web challenges were so hard I'm not even sure I can call myself a web player anymore.
14+
15+
::ctf-overview
16+
::
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
ai_date: 2025-08-17 20:46:37
3+
ai_summary: Exploited pickle protocol differences between Python and C implementations
4+
to bypass restrictions
5+
ai_tags:
6+
- pickle
7+
- protocol
8+
- exploit
9+
created: 2025-08-16T08:40
10+
points: 100
11+
solves: 105
12+
title: Discrepancy
13+
updated: 2025-08-17T20:46
14+
---
15+
16+
We are only allowed 8 bytes of input that has to somehow give different results in `pickle` `_pickle` and `pickletools`.
17+
18+
I'm not gonna do this manually so let's brute force it.
19+
20+
https://github.com/python/cpython/blob/3.13/Lib/pickletools.py#L1153
21+
22+
Just brute forced length 2 ones, then cherry picked op codes that worked and looked nice and did a longer brute force with a subset of opcodes.
23+
24+
```python
25+
import io, itertools, time
26+
from io import BytesIO
27+
import pickle, _pickle, pickletools
28+
from contextlib import redirect_stdout
29+
30+
def py_ok(data: bytes) -> bool:
31+
class SafePyUnpickler(pickle._Unpickler):
32+
def find_class(self, module_name, global_name):
33+
raise RuntimeError("blocked")
34+
try:
35+
SafePyUnpickler(BytesIO(data)).load()
36+
return True
37+
except Exception:
38+
return False
39+
40+
def c_ok(data: bytes) -> bool:
41+
class SafeCUnpickler(_pickle.Unpickler):
42+
def find_class(self, module_name, global_name):
43+
raise RuntimeError("blocked")
44+
try:
45+
SafeCUnpickler(BytesIO(data)).load()
46+
return True
47+
except Exception:
48+
return False
49+
50+
def dis_ok(data: bytes) -> bool:
51+
try:
52+
f = io.StringIO()
53+
with redirect_stdout(f):
54+
pickletools.dis(data)
55+
return True
56+
except Exception:
57+
return False
58+
answers = dict()
59+
alphabet = [0x88, 0x2e, 0x28, 0x90, 0x8f, 0x62, 0x61, 0x80, 0x95, 0x00, 0xff, 0x01, 0x7f]
60+
61+
def test_bytes(b):
62+
s = bytes(b)[:8]
63+
py = py_ok(s); c = c_ok(s); d = dis_ok(s)
64+
return (py,c,d)
65+
66+
start = time.time()
67+
checked = 0
68+
for L in range(1, 9):
69+
print(f"Length {L}...")
70+
for tup in itertools.product(alphabet, repeat=L):
71+
checked += 1
72+
candidate = bytes(tup)[:8]
73+
res = test_bytes(candidate)
74+
if answers.get(res) is None:
75+
answers[res] = candidate
76+
print(f"Found {res} -> {candidate.hex()}")
77+
if len(answers) == 2**3:
78+
print("Found all answers!")
79+
exit(0)
80+
```
81+
82+
```
83+
Length 1...
84+
Found (False, False, False) -> 88
85+
Length 2...
86+
Found (True, True, True) -> 882e
87+
Found (False, False, True) -> 282e
88+
Length 3...
89+
Found (True, True, False) -> 88882e
90+
Length 4...
91+
Found (False, True, True) -> 8828902e
92+
Found (True, False, True) -> 888f622e
93+
Length 5...
94+
Found (False, True, False) -> 888828902e
95+
Found (True, False, False) -> 88888f622e
96+
Found all answers!
97+
```
98+
99+
```python
100+
# ncat --ssl discrepancy.chals.sekai.team 1337
101+
from pwn import *
102+
103+
answers = {(False, False, False): b'\x88', (True, True, True): b'\x88.', (False, False, True): b'(.', (True, True, False): b'\x88\x88.', (False, True, True): b'\x88(\x90.', (True, False, True): b'\x88\x8fb.', (False, True, False): b'\x88\x88(\x90.', (True, False, False): b'\x88\x88\x8fb.'}
104+
conn = remote("discrepancy.chals.sekai.team", 1337, ssl=True)
105+
req = [(True,True,False),
106+
(False,True,True),
107+
(True,False,True),
108+
(False,False,True),
109+
(False,True,False)]
110+
for res in req:
111+
print(conn.recvline())
112+
conn.sendline(answers[res].hex().encode())
113+
114+
print(conn.recvall().decode())
115+
116+
# SEKAI{p1ckleeeeeeeee_3a01fea10fb01a88c1cd554e7372f21ced43b497}
117+
```
118+
119+
```flag
120+
SEKAI{p1ckleeeeeeeee_3a01fea10fb01a88c1cd554e7372f21ced43b497}
121+
```

0 commit comments

Comments
 (0)