423 words
2 minutes
DawgCTF 2026 - I Hate Physics! - Cryptography Writeup

Category: Cryptography

Points: 150

Flag: DawgCTF{therm0dyn4mic5sucks!}

Description: There’s a secret message in these Physics study notes. Can you find it? The flag will be in the format DawgCTF{squarer00tofpi}

The file was plain UTF-8 text, so the first check was just to confirm what kind of artifact it was.

file "/home/rei/Downloads/STUDYME.txt" && stat -c '%s %F %y' "/home/rei/Downloads/STUDYME.txt" && strings "/home/rei/Downloads/STUDYME.txt" | rg -i "flag|ctf|\{[^}]+\}|key|secret|password|BEGIN" --max-columns=200 && xxd "/home/rei/Downloads/STUDYME.txt" | head -n 8
/home/rei/Downloads/STUDYME.txt: Unicode text, UTF-8 text
3194 regular file 2026-04-10 23:01:23.333809842 +0700

Reading the file showed a page of fake physics notes with a lot of awkward line starts and endings. A few lines stood out right away, especially the uppercase sentence ending with { and the later line }]\d\wa\dT, which made the text look staged rather than natural notes. That pushed the solve toward line-based extraction instead of trying to interpret the content as actual physics.

The first pass pulled out broad character classes from the whole file to see whether the hidden text lived in capitals, lowercase, or punctuation.

from pathlib import Path

text = Path('/home/rei/Downloads/STUDYME.txt').read_text(encoding='utf-8')
lines = text.splitlines()
print('line_count', len(lines))
print('first chars:', ''.join((l[0] if l else ' ') for l in lines))
print('last chars:', ''.join((l[-1] if l else ' ') for l in lines))
print('uppercase only:', ''.join(ch for ch in text if ch.isupper()))
print('lowercase only sample:', ''.join(ch for ch in text if ch.islower())[:500])
print('nonalnum:', ''.join(ch for ch in text if ch not in ' \t\r\n' and not ch.isalnum())[:500])
line_count 71
first chars: DwCFtemdnmcscs}hss0protelgTmQ ∆WoQaLaR(sRtUp∆∆KAKAV∆∆WCCaIffU∆d L1 EEET
last chars: agT{hr0y4i5uk!Tiintatfhfa!nn,)),:idp)Sn)d mpysTeTs) )Vle4)T)YTT )) 0586

That was enough to suggest an acrostic-style trick. The first characters already started with DwCF, and the last characters started with agT{, so combining both edges of each line was the next check.

from pathlib import Path

lines = [l for l in Path('/home/rei/Downloads/STUDYME.txt').read_text().splitlines() if l]
msg = ''.join(l[0] + l[-1] for l in lines)
print(msg)
DawgCTF{therm0dyn4mic5sucks!}Thisisn0tpartoftheflag!TnmnQ, )∆)W,o:QiadLpa)RS(ns)Rdt Umpp∆y∆sKTAeKTAsV)∆ ∆)WVClCea4I)fTf)UY∆TdTL)1)E0E5E8T6

That output gives the flag immediately. The string after the closing brace starts with Thisisn0tpartoftheflag!, which is a built-in warning to stop reading after the first complete flag-shaped token.

To make that clear, the last check printed the decoded string as it grew line by line.

from pathlib import Path

lines = [l for l in Path('/home/rei/Downloads/STUDYME.txt').read_text().splitlines() if l]
acc = ''
for i, l in enumerate(lines, 1):
    acc += l[0] + l[-1]
    print(f'{i:02} {(l[0] + l[-1])!r} {acc}')
01 'Da' Da
02 'wg' Dawg
03 'CT' DawgCT
04 'F{' DawgCTF{
05 'th' DawgCTF{th
06 'er' DawgCTF{ther
07 'm0' DawgCTF{therm0
08 'dy' DawgCTF{therm0dy
09 'n4' DawgCTF{therm0dyn4
10 'mi' DawgCTF{therm0dyn4mi
11 'c5' DawgCTF{therm0dyn4mic5
12 'su' DawgCTF{therm0dyn4mic5su
13 'ck' DawgCTF{therm0dyn4mic5suck
14 's!' DawgCTF{therm0dyn4mic5sucks!
15 '}T' DawgCTF{therm0dyn4mic5sucks!}T
DawgCTF 2026 - I Hate Physics! - Cryptography Writeup
https://blog.rei.my.id/posts/139/dawgctf-2026-i-hate-physics-cryptography-writeup/
Author
Reidho Satria
Published at
2026-04-13
License
CC BY-NC-SA 4.0