Step 152. Dreamhack Web (Cumulative 16) — Recognizing Techniques in Disguise
Level 2 — Introduction to Security and Attack Skill Basics | Difficulty ★★★☆☆ | Estimated time: 3 hours
Prerequisites: Step 151 complete. You have solved 8 Dreamhack web problems and written a write-up.
- What you need: a Dreamhack account (at 8 cumulative problems), Burp Suite, a personal wiki, Python 3 (for local reproduction).
- ⚠️ All exercises in this chapter are for your own lab and legal platforms only. Applying them to unauthorized systems is a crime.
- Legal practice grounds: Dreamhack is a legal learning platform that officially issues a per-problem attack-target server, and today’s search-box experiment is a local lab inside my computer. Do not use today’s techniques anywhere outside these two places.
If you solved the first 8 problems, you’ll have noticed — real problems don’t come textbook-shaped. The SQL injection is in a search box, not a login form; the cookie manipulation is disguised as a JWT, not role=guest; the file read hides behind the tame name "image download."
What determines problem-solving speed is not the number of payloads you’ve memorized. It’s the power to guess "what does this feature do inside?" Seeing a search box and picturing a LIKE '%...%' query; seeing a download button and picturing readfile(path). Today is the day we train that guessing power. First we measure "SQLi wearing different clothes" in a local lab, then break 8 more real problems to reach a cumulative 16.
1. Learning Objectives
By the end of this chapter, you will be able to:
- Explain how the same vulnerability hides in different features (search box, download, basket)
- Build the habit of guessing the internal workings (SQL queries, file reads) from a feature
- Record after solving whether your guess was right, and track your guessing power
- Manage stuck problems with a "retry tomorrow" rule
- Complete a cumulative 16 problems and a technique-frequency TOP 3 summary
2. Background Knowledge — Today’s Tools and Concepts
Today’s Tools at a Glance
| Category | Details |
|---|---|
| Language/environment | Dreamhack wargame + Python 3 + Flask & sqlite3 (local reproduction lab) |
| Today’s commands | The ' OR 1=1 -- injection payload, Burp Repeater, the "guess" column of a write-up |
| Concepts needed | Vulnerabilities disguised as features, LIKE queries, guessing internal workings, technique-frequency analysis |
| Today’s artifact | Cumulative 16 problems + a guess-hit record table + a technique TOP 3 |
2-1. Vulnerabilities Change Clothes
The techniques you learned in Steps 134–150 arise not from "which screen" they’re on but from "which code pattern." Build SQL by string concatenation and anywhere is injectable — a login form, a search box, a product-sort dropdown.
So the first question in solving a real problem is not "what’s this problem’s vulnerability?" It’s "what code does each feature on this screen run inside the server?" A search box runs a DB search query, an image view runs a file read, an exchange-rate calculator runs an external request. See the feature and you see the code; see the code and the vulnerability candidates are set.
2-2. The Guess-Verify Loop
The training method we settle in today.
① Feature list — enumerate every input and button on this page
② Guess internal workings — for each feature, write one line of "probably this code" in words
③ Technique matching — attach a learned technique fitting that code pattern
④ Experiment — test the matched payload
⑤ Scoring — after solving, record whether the guess in ② was right
The core is writing ② "in words first." A guess in your head teaches nothing when wrong, but a written-down guess can be scored. Score ten problems this way and the biases of your guessing (e.g., "I underestimate file paths") become visible as data.
2-3. The Time Limit of Deployment-Type Problems
Many of Dreamhack’s web problems are the deployment type, spinning up a temporary server each time you connect (screen example — check the platform’s screen yourself). The server address expires after a set time, and when it expires your solve isn’t lost — you just get a new server. But if it expires right before you grab the flag, you must break in from the start, so jot down your progress (the path to the payloads that worked) as you go.
3. Follow Along
3-1. Local Lab — SQLi Hidden in a Search Box
Let’s make firsthand what "changing clothes" means. An experiment combining Steps 92–93’s SQL knowledge with Step 104’s injection. search_sqli_lab.py:
import sqlite3
from flask import Flask, request
app = Flask(__name__)
db = sqlite3.connect(":memory:", check_same_thread=False)
db.execute("CREATE TABLE products (name TEXT, price INTEGER, note TEXT)")
db.executemany("INSERT INTO products VALUES (?, ?, ?)", [
("Apple", 1000, "Fresh"),
("Banana", 1500, "Sweet"),
("Secret Item", 999999, "flag{search_sqli_too}"),
])
db.commit()
@app.route("/search")
def search():
q = request.args.get("q", "")
# vulnerable: string concatenation — the same hole in a 'search box', not a login form
sql = f"SELECT name, price FROM products WHERE name LIKE '%{q}%'"
try:
rows = db.execute(sql).fetchall()
except sqlite3.Error as e:
return f"DB error: {e}\nExecuted SQL: {sql}\n"
out = [f"Executed SQL: {sql}", "--- Results ---"]
out += [f"{name} ({price} won)" for name, price in rows]
return "\n".join(out) + "\n"
if __name__ == "__main__":
app.run(port=5494)
3-2. Comparing a Normal Search and an Injection
Start the server (python search_sqli_lab.py) and search with a browser or Python. First, a normal search:
http://127.0.0.1:5494/search?q=Apple
Output (measured 2026-09-09):
Executed SQL: SELECT name, price FROM products WHERE name LIKE '%Apple%'
--- Results ---
Apple (1000 won)
Now put not a search term but a fragment of SQL into the search box:
http://127.0.0.1:5494/search?q=' OR 1=1 --
Output (measured 2026-09-09):
Executed SQL: SELECT name, price FROM products WHERE name LIKE '%' OR 1=1 -- %'
--- Results ---
Apple (1000 won)
Banana (1500 won)
Secret Item (999999 won)
How to read it: the input’s quote (') closed the quote of LIKE '%, and OR 1=1 added an "always true," so every product came out. The trailing %' was commented out with --, dodging a syntax error. The very technique learned on a login form landed as-is on a search box with a completely different screen. The hidden Secret Item — in the field, this is where the flag sits.
Why: this experiment’s point is not the payload but the location. The vulnerability wore the clothes of a "search feature," but its essence was Step 104’s string-concatenated SQL. The ability to strip off the clothes is the guessing power of 2-2.
3-3. Building a Guess-Hit Record Table
Make guess-log.md in your personal wiki and prepare a table.
| Problem | Feature | Internal-workings guess | Matched technique | Hit? | If wrong, the actual |
|------|------|--------------|-----------|-------|--------------|
| Example | Product search box | LIKE query concatenation | SQLi | O | |
| Example | Image download | readfile(path) | Path manipulation (LFI) | X | Actually a filename-whitelist bypass |
Fill the first four columns before starting a problem, and the last two after solving it. This table is today’s core artifact.
3-4. Eight Real Problems — Guessing-Power Training
Pick 8 difficulty 1–2 problems from Dreamhack’s web category. For each problem, the procedure is:
① Recon — every page, source, cookies, APIs in the Network tab
② Feature list — enumerate input boxes, buttons, links
③ Record guesses — write "probably this code" in guess-log.md
④ Experiment — test the matched technique's payloads (learned ones: SQLi, cookies, source reading, IDOR, JWT...)
⑤ Scoring — after solving, record whether the guess hit
For problems that provide source code (ones with a file-download button), always read the code to the end. The hint is not in the description but in the code — read which inputs the validation function filters out, and the bypass becomes visible.
3-5. Managing Stuck Problems — The Retry-Tomorrow Rule
If there’s no progress for 30+ minutes, stop. Don’t look at the solution — leave a note like this:
■ Awaiting retry: (problem name)
- What I tried: (list of payloads)
- Next hypothesis candidates: (what I haven't tried yet)
- Retry date: tomorrow
Look at the solution and that problem drops out of your training data — because what grows is "reading power," not "finding power." Look again the next day with reset eyes, and it’s amazing how often things become visible. If you’re stuck even on the retry, then read the solution and add the technique you learned to your technique cards (Step 105).
4. Missions & Exercises
Mission — Cumulative 16 and Guessing-Power Data
- Expose the
Secret Itemvia search-box injection in the local lab - Solve 8 more Dreamhack web problems to reach a cumulative 16
- For all 8 problems, record "feature list → internal-workings guess" before solving
- After solving, score whether each guess hit, and for wrong guesses write the actual answer alongside
- Count technique frequency across the 16 problems and organize a TOP 3
Exercises
Exercise 1. Explain why ' OR 1=1 -- worked even in a search box in the 3-2 experiment, citing the executed SQL string as evidence.
Exercise 2. Explain the meaning of "vulnerabilities change clothes," in terms of the relationship between payloads and code patterns.
Exercise 3. Why is writing a guess down first better than guessing in your head?
Exercise 4. Explain why you don’t look at a stuck problem’s solution right away, from the "training data" perspective.
5. Model Answers & Completion Criteria
Mission Model Answer
Item 1 is exactly the 3-2 measurement — q=' OR 1=1 -- exposes all three rows, among them the Secret Item.
Items 2–4 proceed on the platform. Your guess-log.md passes at this density (screen example):
| cookie-2 | permission cookie | simple string comparison | cookie value change | O | |
| photo-dl | download | readfile(parameter) | LFI ../../ | X | Actually a filter bypass after ?file= |
An example TOP 3 summary for item 5 (screen example — use your actual data):
Technique frequency across 16 problems: cookie/session manipulation 5, SQLi 4, source/file reading 3, other 4
→ TOP 3: cookie/session, SQLi, file reading
How to verify: ① is the profile’s solve count 16 or more? ② are 8 rows of the guess-log’s "Hit?" column filled? ③ does the TOP 3 match the table’s actual counts — the total must be 16.
Exercise Answers
Answer 1. Because the server concatenated the input into the SQL string without validation. In the measurement, the executed SQL was WHERE name LIKE '%' OR 1=1 -- %' — my input’s quote closed the string and OR 1=1 added a true condition, returning every row. Whether the feature is search or login, if the code pattern "builds SQL by concatenating input" is the same, the same attack holds.
Answer 2. A payload binds to a code pattern, not to a screen. The string-concatenated-SQL pattern can exist in a login form, a search box, or a sort option alike, and if the pattern matches, the same payload lands. So you must guess the internal code (the body), not the problem’s screen (the clothes).
Answer 3. Because only a written-down guess can be scored. As scoring accumulates, "which types of guesses I’m good and bad at" emerges as data, and weak types can be trained intensively. A guess in your head vanishes without a trace the moment it’s wrong, repeating the same errors.
Answer 4. Because a problem whose solution you’ve seen can no longer be used as data measuring "the power to find the vulnerability yourself." Re-solving while knowing the answer trains reproduction ability, not discovery ability. Record it and retry, and that problem remains valid training data.
Completion Criteria Checklist
- [ ] I exposed a hidden row via SQLi in a search box
- [ ] I can state the "feature → internal code guess → technique matching" procedure
- [ ] I made and used a guess-hit record table
- [ ] I’ve built the habit of reading source-provided problems’ code to the end
- [ ] I manage stuck problems with the "retry tomorrow" rule
- [ ] I understand deployment servers’ expiry and re-issuance
- [ ] Mission: cumulative 16 problems + technique TOP 3 summary complete
6. Common Pitfalls & Fixes
Wall 1. I put in an injection and only got a DB error
Symptom (local lab, 2026-09-09 measured family):
DB error: unrecognized token: ...
Executed SQL: SELECT ... LIKE '%' ...
Cause: you put in only a quote with no follow-up handling, breaking the SQL syntax. The error is actually good news — proof that my input enters the SQL.
Fix: comment out the remainder with -- (or #, depending on the DB). First checking whether a lone ' causes an error is the first test of injection detection.
Wall 2. A deployment-type problem server dies mid-way
Symptom (output example): a server that was fine stops responding and connections drop.
Cause: the temporary server’s lifespan ended.
Fix: get it re-deployed from the problem page. To avoid losing it right before the flag, the habit of jotting down successful-stage payloads as you go is the answer.
Wall 3. My guesses are wrong every time
Cause: normal. Guessing power is an instinct that only accumulates with data, so a low hit rate for the first 10 problems is the standard.
Fix: make "did I write a guess" the completion criterion, not the hit rate. Once 10 pairs of wrong guess + actual answer pile up, number 11 onward changes.
Wall 4. Source code was given but I don’t know where to look
Cause: you’re reading the code "from the top."
Fix: read it backward. ① Where is the flag (a file? an environment variable? in the code?) ② the conditional that reaches it ③ the input that passes that condition. This reverse tracing is the standard for source-reading problems.
Wall 5. I put in a payload and nothing changes at all
Cause: the server is filtering, or the payload went somewhere else (e.g., a log rather than the response), or the request format (JSON, etc.) is wrong.
Fix: compare the original request’s and your request’s responses side by side in Burp Repeater. If even one of status code, length, or body differs, there’s a reaction. If completely identical, the input never reached the code — check the actually transmitted values in the Network tab.
7. Summary
Today’s Concepts
| Concept | One-line explanation |
|---|---|
| Technique disguise | The same vulnerability appears wearing different features’ clothes |
| Internal-workings guess | Training to imagine the server code from a feature |
| Guess-hit record | Turning guessing power into data by writing guesses and scoring them |
| Deployment-type problem | A temporary server issued per connection — with expiry and re-deploy |
| Retry rule | For stuck problems, don’t read the solution — retry the next day |
Today’s Commands & Payloads
| Command/payload | What it does |
|---|---|
' (a single quote) |
Injection detection — a DB-error induction test |
' OR 1=1 -- |
Neutralizing LIKE/WHERE conditions |
/search?q=... form |
Passing a search term as a GET parameter |
| guess-log.md table | Recording guess-hit scoring |
| Awaiting-retry memo | Managing the state of stuck problems |
An Instinct More Important Than Commands
When you see a screen, imagine the code. A search box is a LIKE query, a download button is a readfile, a basket quantity is a single line of multiplication. The person whose imagining is fast solves problems fast — and this instinct is not talent but the accumulation of scored guesses. A wrong guess is an asset too. From today, your most important tool is not a payload list but the one line of "probably this code" you write first for every problem.
Once every box is checked, Step 152 is complete. Click the checkbox in the sidebar to save your progress.