Step 152. Dreamhack Web (Cumulative 16) — Recognizing Techniques in Disguise

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

  1. Expose the Secret Item via search-box injection in the local lab
  2. Solve 8 more Dreamhack web problems to reach a cumulative 16
  3. For all 8 problems, record "feature list → internal-workings guess" before solving
  4. After solving, score whether each guess hit, and for wrong guesses write the actual answer alongside
  5. 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.