← Back to Writeups
HTBN/ASteganography

I Hate Physics!

XESXOR8/23/20269 min read
#steganography#htb#n/a

I Hate Physics!

Platform: Dawgctf | Category: Steganography | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-04-10 | Status: Solved Techniques: first_and_last_character_acrostic, leet_speak_decoding, recognition_of_deliberate_text_anomalies

Summary

A plain-text file of messy physics study notes hides the flag as a first-and-last-character acrostic: taking the first character and the last character of each of the first 15 lines and concatenating them yields DawgCTF{REDACTED} — 'thermodynamics sucks!' in leet speak, matching the task title 'I Hate Physics!'. Every 'error' in the notes — wrong variables, dangling letters, misspellings like 'Klevin', trailing terms like '*tau', the nonsense line 15 — exists only to force the right first/last characters on each line.

Recon

Port scan

nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: dawgctf | ID: 20260410_dawgctf_i_hate_physics
  • Tags: steganography, text_steganography, leet_speak, acrostic, first_last_char_acrostic, physics_notes, study_notes, dawgctf
  • Indicators: Plain text file of messy study notes in a technical subject (physics/math/chemistry) with many subtle errors, Task description hints at a 'secret message' inside perfectly normal-looking notes, Individual lines have conspicuous oddities: dangling single letters, extra characters, unexplained trailing symbols, misspellings like 'Klevin' or 'avagadro, First characters of the first non-empty lines happen to match the prefix of the flag format (e.g. D, w, C, F for DawgCTF), At least one line is pure junk or regex-looking gibberish (line 15: }]\\d\\wa\\dT) whose only job is to provide the closing brace
  • Source: 20260410_dawgctf_i_hate_physics.md

Foothold

Vulnerability / Misconfiguration

  1. First_and_last_character_acrostic
  2. Leet_speak_decoding
  3. Recognition_of_deliberate_text_anomalies
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • first_and_last_character_acrostic
  • leet_speak_decoding
  • recognition_of_deliberate_text_anomalies
  • Tags: steganography, text_steganography, leet_speak, acrostic, first_last_char_acrostic, physics_notes, study_notes, dawgctf

Original Writeup

<details><summary>Click to expand original content</summary>

Description

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

File: STUDYME.txt

The provided STUDYME.txt is a 71-line plain-text file that looks like someone's thermodynamics study notes: kinetic energy, work, heat capacities at constant pressure/volume, ideal gas law, Boltzmann's entropy formula, a fully-worked ice + water mixing problem, and so on. The flag format example squarer00tofpi (i.e. "square root of pi" in leet speak) strongly hints that the hidden content is a short English phrase written with leet substitutions.

Analysis

1. First impression — many things are "wrong"

Reading the first 15 lines carefully:

D=1/2mv^2 (force * displacement) = 1/2 * mass * velocity^2 + alpha
w=fd (force * displacement) with respect to displacement lag
Cp=20.79 J/K/Mol for a constant pressure ONLY FOR OUTPUT
FINAL TEMPERATURE ALWAYS COMES FIRST BECAUSE THE TEMPERATURE DELTA IS INSIDE {
temperature min, temperature max}, like with
e=u+pVr
m=0
dU=mcdT and remember that sometimes mcdT can be a dy
nA is number of moles of gas A/B^4
mA*cA*∆T=cB*cB*∆T when two things are equalizing i.e and indirect carnot cycli
c, such as with the following equation: 2500kg*cA*(500-400)=cB*cB*∆T*5
s=ksubb * ln * omega * tau
cv=12.47J/K/Mol for a constant vol, Klevin is k
s=integral from vi to vf of (1/T *dU) for a general delta!
}]\d\wa\dT

Almost every line contains something that does not belong in a physics textbook:

  • Line 1 uses D as a symbol for kinetic energy and tacks on a stray + alpha.
  • Line 2 ends with the ungrammatical "with respect to displacement lag".
  • Line 3 ends in the ALL-CAPS fragment "ONLY FOR OUTPUT".
  • Line 4 is pure ALL-CAPS meta text "FINAL TEMPERATURE ALWAYS COMES FIRST BECAUSE THE TEMPERATURE DELTA IS INSIDE {" and ends on a lone opening brace.
  • Line 6 is e=u+pVr — the real enthalpy formula is H = U + pV, the trailing r is unexplained.
  • Line 7 is the tiny and pointless m=0.
  • Line 8 ends in the random fragment "can be a dy".
  • Line 9 has A/B^4, which is not a real expression.
  • Line 10 breaks the word "cyclic" unnaturally across two lines (cycli / c,).
  • Line 11 ends with a stray *5.
  • Line 12's Boltzmann entropy formula has an extra * tau.
  • Line 13 misspells Kelvin as "Klevin" and then tacks on "is k".
  • Line 14 ends with "for a general delta!".
  • Line 15 is pure regex-looking junk: }]\d\wa\dT.

These anomalies are too consistent to be sloppy note-taking — they are the encoding.

2. The instruction hints are red herrings

Several ALL-CAPS fragments look like instructions:

  • ONLY FOR OUTPUT
  • FINAL TEMPERATURE ALWAYS COMES FIRST
  • REMEMBER - YOU CAN SET FUNCTIONS EQUAL TO ANOTHER AND CANCEL LIKE TERMS
  • USE KELVIN FOR ENTROPY

It is tempting to interpret them as instructions for the extraction ("output only the caps", "cancel duplicates", "convert to Kelvin"). None of these lead anywhere. They exist only to provide the correct uppercase first letter at specific line positions (see step 4).

3. The key observation — flag prefix in the line starts

The flag format is DawgCTF{...}. Writing down the first character of each of the first four lines gives:

L1: D
L2: w
L3: C
L4: F

So lines 1..4 already supply D, w, C, F — every capital letter of DawgCTF except a, g, T. That strongly suggests an acrostic, but single first characters alone are not enough.

4. The actual encoding — first and last character of each line

Take the first character and the last character of each of the first 15 lines:

LineLine endingFirstLastPair
1...velocity^2 + alphaDaDa
2...displacement lagwgwg
3...ONLY FOR OUTPUTCTCT
4...DELTA IS INSIDE {F{F{
5...like withthth
6e=u+pVrerer
7m=0m0m0
8...can be a dydydy
9...of gas A/B^4n4n4
10...indirect carnot cyclimimi
11...=cBcB∆T*5c5c5
12s=ksubb * ln * omega * taususu
13...constant vol, Klevin is kckck
14...for a general delta**!**s!s!
15}]\d\wa\dT}(distractor T)}

Concatenating all pairs:

Da + wg + CT + F{ + th + er + m0 + dy + n4 + mi + c5 + su + ck + s! + }
= DawgCTF{REDACTED}

Decoding the leet (0o, 4a, 5s) gives "thermodynamics sucks!" — exactly what a frustrated student who "hates physics" would write. The task title is literal.

5. Why each oddity is there

Every strange element in the first 15 lines exists solely to force the right first/last character pair:

LineWhat was insertedWhy
1+ alphaends in a
2with respect to displacement lagends in g
3ONLY FOR OUTPUTends in T
4ALL CAPS FINAL TEMPERATURE ALWAYS COMES FIRST BECAUSE THE TEMPERATURE DELTA IS INSIDE {starts with F, ends with {
5, like withends in h
6unexplained trailing r in e=u+pVrends in r
7m=0 (tiny formula)supplies both m and 0
8trailing ...can be a dyends in y
9nonsensical A/B^4ends in 4
10carnot cycli (word broken across lines)ends in i
11trailing *5ends in 5
12extra * tau in Boltzmann's formulaends in u
13, Klevin is k (with the deliberate misspelling "Klevin")ends in k
14for a general delta!ends in !
15the whole line }]\d\wa\dT is junkfirst char } closes the flag; the rest is a distractor

Lines 16–71 are cover text: more (still buggy) physics, two more ALL-CAPS "REMEMBER" hints, USE KELVIN FOR ENTROPY, and a concrete ice + water mixing problem that actually solves to T = 334.915873016. None of that contributes to the flag.

Solution

Python solver

#!/usr/bin/env python3
"""Solver for DawgCTF SP26 'I Hate Physics!' — first-and-last-char acrostic."""

from pathlib import Path


def solve(path: str) -> str:
    lines = Path(path).read_text(encoding='utf-8').splitlines()
    flag = ''
    for i, line in enumerate(lines[:15], 1):
        if not line:
            continue
        first = line[0]
        last = line[-1]
        if i == 15:
            # Line 15 is `}]\d\wa\dT`: only the first char (`}`) is part of the flag
            flag += first
        else:
            flag += first + last
        print(f'L{i:2d}: first={first!r:>4}  last={last!r:>4}  -> {first + (last if i != 15 else "")!r}')
    return flag


if __name__ == '__main__':
    flag = solve('STUDYME.txt')
    print(f'\nFlag: {flag}')
    # DawgCTF{REDACTED}

TL;DR

  1. Look at the first character of each of the first few lines: D, w, C, F — matches the DawgCTF prefix of the flag format, so an acrostic is almost certainly in play.
  2. Lines 5–15 don't start with the expected letters for the inside of {...}, so first-char-only isn't enough.
  3. Take first char + last char of each of the first 14 lines, plus first char of line 15 (}).
  4. Concatenate: DawgCTF{REDACTED}.
  5. Ignore the ALL-CAPS "instruction" fragments, the }]\d\wa\dT regex-looking line, and the ice + water entropy calculation at the bottom — all red herrings.
</details>

Auto-tracked: saved to WriteUps; run /xesor-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR