Step 151. 드림핵 웹 입문 — 첫 실전 문제

Step 151. 드림핵 웹 입문 — 첫 실전 문제

Level 2 — 보안 입문과 공격 스킬 기초 | 난이도 ★★☆☆☆ | 예상 소요 시간 2.5시간

전제: Step 150까지 마쳤다. 개발자 도구로 HTML 소스와 쿠키를 볼 수 있고, Base64 디코딩과 간단한 요청 조작을 안다.

  • 준비물: 인터넷 연결, 드림핵 계정(오늘 만듭니다), 개발자 도구, 개인 위키(Write-up 저장소).
  • ⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다.
  • 합법 연습장 안내: 드림핵(dreamhack.io)은 문제마다 "공격해도 되는 서버"를 공식적으로 발급해 주는 합법 학습 플랫폼입니다. 문제 서버 주소와 내 컴퓨터의 로컬 랩 외에는 오늘의 기술을 쓰지 않습니다.

지금까지의 무대 — Bandit, Natas, DVWA, Juice Shop — 은 전부 "정해진 교과서"였습니다. 오늘부터는 "남이 낸 시험 문제"를 풉니다. 드림핵은 한국어로 된 CTF(해킹 방어 대회 형식의 문제 풀이) 플랫폼으로, 문제마다 실제로 공격할 수 있는 임시 웹 서버를 발급해 줍니다. 취약점을 찾아 서버 어딘가에 숨겨진 플래그(flag)를 읽어 제출하면 정답입니다.

무서울 것 없습니다. 첫 문제들은 여러분이 이미 아는 기술 그대로입니다 — 소스 보기, 쿠키 읽기, 간단한 입력 조작. 오늘은 플랫폼 사용법을 익히고, 첫 문제 유형을 로컬 랩에서 복습한 뒤, 실전 문제 8개를 깨는 것이 목표입니다.


1. 학습 목표

이 챕터를 끝내면 다음을 할 수 있습니다:

  • 드림핵 워게임의 문제 구성 요소(제목·설명·URL·플래그 제출)를 안다
  • 문제의 제목과 설명에서 공격 대상 힌트를 읽어 낸다
  • 소스 보기·쿠키 해독 유형을 로컬 랩에서 재현해 푼다
  • 정찰 → 가설 → 실험 → 플래그의 풀이 사이클을 실전 문제에 적용한다
  • 정해진 형식의 Write-up을 작성한다

2. 배경 지식 — 오늘의 도구와 개념

오늘의 도구 한눈에 보기

구분 내용
언어·환경 드림핵 워게임(브라우저) + 파이썬 3 + Flask(로컬 복습 랩)
오늘의 명령 개발자 도구 소스 보기, Application 탭의 쿠키, base64.b64decode()
필요한 개념 CTF와 플래그, DH{...} 형식, 문제 배포 서버, 풀이 사이클
오늘의 산출물 웹 문제 8개 해결 + Write-up 2편

2-1. CTF와 플래그 — 정답의 모양

CTF 문제의 정답은 플래그라는 특별한 문자열입니다. 드림핵의 플래그는 DH{여기에_정답이_들어감} 형식입니다. 문제 서버를 공격해 이 문자열을 찾아낸 뒤, 문제 페이지의 제출 칸에 넣으면 점수를 받습니다.

플래그는 "내가 이 서버의 비밀에 실제로 도달했다"는 증거입니다. 화면 캡처나 설명이 아니라 서버가 숨겨 둔 문자열 자체를 가져와야 하니, 풀이에는 변명의 여지가 없습니다. 이것이 CTF가 실력의 척도가 되는 이유입니다.

2-2. 문제 페이지 읽는 법

드림핵의 웹 문제는 대개 이렇게 구성됩니다 (화면 예시 — 실제 화면은 가입 후 확인):

제목: cookie-monster        난이도: ★ 1    풀이 수: 1,234명
설명: 이 사이트는 쿠키로 권한을 관리합니다. 관리자만 플래그를 볼 수 있습니다.
[서버 접속하기] → http://host3.dreamhack.games:12345/
[플래그 제출] DH{____________________}

제목과 설명이 곧 힌트입니다. cookie라는 단어가 보이면 쿠키 조작 문제이고, source가 보이면 소스 읽기 문제입니다. "난이도 1부터"라는 규칙을 지키세요 — 처음부터 어려운 문제를 고르면 배우기 전에 멘탈이 깨집니다.

2-3. 풀이 사이클 — 실전판 네 박자

Step 96의 사이클이 웹 문제용으로 진화했습니다.

① 정찰 — 문제 서버의 페이지를 전부 둘러본다 (소스 보기, 링크, 폼, 쿠키)
② 가설 — "이 기능은 내부에서 무엇을 할까?" 취약점 후보를 적는다
③ 실험 — 입력을 바꾸고, 쿠키를 고치고, Burp로 요청을 다시 보낸다
④ 플래그 — DH{...}를 찾아 제출하고, 풀이를 기록한다

초보는 ①을 10초 만에 끝내고 ③만 반복합니다. 난이도 1 문제의 플래그는 대부분 ① 정찰만 철저히 해도 보입니다. 먼저 "읽는" 사람이 이깁니다.

2-4. 첫 문제 유형 미리보기

난이도 1~2의 웹 문제는 세 가지 유형이 주를 이룹니다.

유형 문제가 숨긴 것 여러분이 할 일
소스 읽기 HTML 주석·JS 파일에 플래그 개발자 도구로 소스 전체 읽기
쿠키 role=guest 같은 권한 쿠키 값을 디코딩하고, 바꿔치기
간단한 입력 조작 검증 없는 입력창 SQLi·명령 문자 등 시험 입력

전부 이미 배운 것들입니다. 오늘 로컬 랩에서 이 유형들을 다시 한번 손에 익히고 실전으로 갑니다.


3. 따라 하기

3-1. 로컬 랩 — 소스에 숨겨진 플래그 찾기

드림핵 문제가 어떻게 생겼는지, 똑같은 구조를 내 컴퓨터에 만듭니다. firstprob_lab.py:

from flask import Flask, make_response

app = Flask(__name__)

@app.route("/")
def index():
    html = """<!doctype html>
<html><body>
<h1>Welcome!</h1>
<p>로그인하면 더 많은 기능이 열립니다.</p>
<!-- TODO: 배포 전 삭제. 임시 관리자 메모: flag{view_source_is_free} -->
</body></html>"""
    resp = make_response(html)
    resp.set_cookie("session_role", "Z3Vlc3Q=")  # base64("guest")
    return resp

if __name__ == "__main__":
    app.run(port=5493)

실행 후(python firstprob_lab.py) 브라우저로 http://127.0.0.1:5493/에 접속합니다. 화면에는 "Welcome!"과 한 줄의 안내만 보입니다. 이제 정찰 모드로 — 개발자 도구(F12)를 열어 Elements 탭에서 HTML 전체를 봅니다.

서버가 실제로 보낸 소스 (2026-09-09 실측):

<!doctype html>
<html><body>
<h1>Welcome!</h1>
<p>로그인하면 더 많은 기능이 열립니다.</p>
<!-- TODO: 배포 전 삭제. 임시 관리자 메모: flag{view_source_is_free} -->
</body></html>

읽는 법: 브라우저 화면에는 없는 다섯 번째 줄이 소스에는 있습니다. <!-- ... -->는 HTML 주석으로 화면에 그려지지 않지만, 서버는 분명히 보냈습니다. 실전에서도 개발자 메모, 임시 비밀번호, 숨겨진 경로가 주석에서 단골로 나옵니다.

3-2. 쿠키 읽고 해독하기

같은 서버가 응답에 쿠키도 실어 보냈습니다. 개발자 도구 Application 탭 → Cookies에서 확인하거나, 응답 헤더로 봅니다.

응답 헤더 (2026-09-09 실측):

Set-Cookie: session_role=Z3Vlc3Q=; Path=/

값이 Base64 모양입니다 (끝의 =이 특징). 파이썬으로 해독합니다.

import base64
base64.b64decode("Z3Vlc3Q=").decode()

출력 (2026-09-09 실측):

guest

읽는 법: "당신의 권한은 guest"라는 선언이 내 브라우저 안에 들어 있습니다. 다음 질문은 자연스럽습니다 — 이 값을 YWRtaW4=(base64로 "admin")으로 바꾸면? 쿠키는 클라이언트가 마음대로 고칠 수 있고, 서버가 검증 없이 믿으면 권한 상승이 됩니다. Natas(Step 102~104)에서 이미 해본 바로 그 공격입니다.

: 쿠키 값을 보는 순서를 정해 두세요. ① Base64 모양인가 → 디코딩 ② 점이 두 개인가 → JWT(Step 150) ③ 둘 다 아니면 값 자체를 조작. 세 갈래면 난이도 1~2 쿠키 문제의 대부분을 커버합니다.

3-3. 드림핵 가입과 첫 문제 배포

이제 실전입니다 (화면 예시 — 플랫폼 화면은 여러분이 직접):

  1. dreamhack.io에 접속해 회원가입 (이메일 인증)
  2. 상단 메뉴 Wargame → 카테고리에서 web 선택
  3. 난이도 순으로 정렬해 가장 쉬운 문제부터 클릭
  4. 문제 페이지의 서버 접속하기 버튼 → 임시 서버 주소 발급

읽는 법: 발급되는 주소(http://hostN.dreamhack.games:포트/ 형태)는 여러분만의 일회성 연습 서버입니다. 일정 시간이 지나면 만료되니, 만료되면 다시 발급받으면 됩니다. 이 주소는 공격이 허가된 유일한 목표입니다.

3-4. 첫 문제 풀이 사이클 적용

난이도 1 문제 하나를 골랐다고 칩시다. 사이클을 의식적으로 적용합니다.

① 정찰: 메인 페이지 열기 → F12로 HTML 소스 전체 읽기 → Application 탭의 쿠키 확인
        → robots.txt 도 접속해 보기 (/robots.txt)
② 가설: "쿠키 이름이 role이네. 권한 문제겠다" / "주석이 있네. 소스 문제겠다"
③ 실험: 쿠키 값 디코딩·변경, 입력창에 시험 값, Burp로 요청 재전송
④ 플래그: DH{...} 발견 → 문제 페이지에 제출 → 기록

문제가 안 풀리면 ①으로 돌아가는 것이 정석입니다. "정찰에서 놓친 것이 있다"가 막힘의 원인 1위입니다.

3-5. Write-up 첫 작성

문제를 풀었다면, 기억이 뜨거울 때 바로 씁니다. 개인 위키에 dreamhack-001.md를 만들고 이 형식으로:

# 문제: (제목) — 난이도 ★
- **상황**: (문제 설명 한 줄 요약)
- **정찰에서 본 것**: (소스·쿠키·폼 중 눈에 띈 것)
- **가설**: (어떤 취약점이라고 생각했는가)
- **시도한 것**: (실제로 한 것, 실패 포함)
- **성공한 페이로드**: (결정적 한 수)
- **배운 점**: (다음에 바로 쓸 한 문장)

"시도한 것"에 실패를 꼭 적으세요. 실패 목록은 다음 문제에서 "이건 해봤다"를 지워 주는 자산입니다. 플래그 문자열 자체는 공개 장소에 올리지 않는 것이 CTF 예의입니다 — 개인 위키에만 보관하세요.


4. 미션과 연습문제

미션 — 첫 8문제와 기록 습관

  1. 로컬 랩(firstprob_lab.py)에서 소스 속 플래그와 쿠키 값을 전부 찾아냅니다
  2. 드림핵에 가입하고 웹 카테고리 난이도 1~2 문제 8개를 해결합니다
  3. 8문제 모두에서 정찰 → 가설 → 실험 → 플래그 네 박자를 메모에 남깁니다
  4. 그중 2문제는 3-5 형식의 Write-up으로 완성합니다

연습문제

문제 1. 플래그가 "증거" 역할을 하는 이유를 설명해 보세요. 왜 화면 캡처로는 부족한가요?

문제 2. 브라우저 화면에는 보이지 않는데 HTML 소스에는 있는 정보는 어떻게 존재할 수 있나요? 3-1의 실측을 근거로 설명해 보세요.

문제 3. 쿠키 값을 만났을 때의 3갈래 판별 순서(Base64? JWT? 원시 조작?)를 각각의 식별 특징과 함께 써 보세요.

문제 4. 문제가 안 풀릴 때 사이클의 어느 박자로 돌아가야 하는지, 그 이유와 함께 설명해 보세요.


5. 모범 답안과 완료 기준

미션 모범 답안

1번의 로컬 랩 정답 (2026-09-09 실측): 소스 주석의 flag{view_source_is_free}, 쿠키 session_role=Z3Vlc3Q=guest. 찾는 절차는 3-1·3-2 그대로입니다.

2~3번은 플랫폼에서 진행합니다. 8문제의 메모가 이런 모양이면 합격입니다 (화면 예시):

문제 A — 정찰: index 페이지 + 쿠키 role=guest 발견 / 가설: 쿠키 조작
        / 실험: role을 admin으로 변경 후 새로고침 / 플래그: 제출 완료

4번 Write-up의 "가설" 칸이 비어 있으면 사이클 ②를 건너뛴 것입니다 — 되돌아가서 채우세요.

검증하는 법: ① 드림핵 프로필의 해결 수가 8 이상인가. ② Write-up 2편에 "성공한 페이로드"가 구체적으로 적혀 있는가. ③ 각 문제 메모에 네 박자가 전부 있는가.

연습문제 해답

문제 1 해답. 플래그는 서버 안에 숨겨진 문자열 자체이므로, 그것을 제시했다는 것은 서버의 비밀 지점에 실제로 도달했다는 유일한 증거입니다. 화면 캡처는 조작·모방이 가능하지만, DH{...} 안의 무작위 문자열은 해당 서버를 뚫지 않고는 알 수 없습니다.

문제 2 해답. 서버는 HTML 문서 전체를 보내고, 브라우저는 그중 화면에 그릴 부분만 렌더링합니다. <!-- --> 주석은 "그리지 말라"는 표시일 뿐 전송은 됩니다. 3-1 실측에서 화면에는 없는 관리자 메모가 소스에는 그대로 있었습니다 — 화면은 서버 응답의 부분집합입니다.

문제 3 해답. ① 끝이 =이거나 영숫자++// 조합이면 Base64 후보 → 디코딩해 의미를 읽는다. ② 점(.)이 두 개면 JWT → Step 150의 해부 절차. ③ 둘 다 아니면 role=guest 같은 평문 → 값 자체를 바꿔 실험한다. 식별 특징은 각각 "패딩 문자", "점 두 개", "읽히는 평문"입니다.

문제 4 해답. 정찰(①)로 돌아갑니다. 난이도 1~2 문제의 막힘은 대부분 "못 푸는 것"이 아니라 "안 본 것" — 읽지 않은 JS 파일, 확인하지 않은 쿠키, 시도하지 않은 경로(robots.txt 등)가 원인입니다. 실험을 더 하는 것은 가설이 맞을 때만 유효합니다.

완료 기준 체크리스트

  • [ ] 드림핵 문제 페이지의 구성 요소(제목·설명·서버 주소·제출 칸)를 안다
  • [ ] DH{...} 플래그 형식을 알고 제출할 수 있다
  • [ ] 개발자 도구로 HTML 주석 속 숨은 정보를 찾았다
  • [ ] 쿠키 값을 Base64로 해독하고 변경 실험을 했다
  • [ ] 정찰 → 가설 → 실험 → 플래그 사이클을 순서대로 적용했다
  • [ ] 문제 서버 주소가 일회성·만료됨을 이해한다
  • [ ] 미션: 웹 문제 8개 해결 + Write-up 2편 완성

6. 흔한 실수와 해결

벽 1. 문제 서버에 접속하면 연결이 안 된다

증상 (출력 예시):

이 사이트에 연결할 수 없음 / ERR_CONNECTION_TIMED_OUT

원인: 배포된 임시 서버가 만료됐거나, 회사·학교 네트워크가 특이 포트를 막고 있습니다.
해결: 문제 페이지에서 서버를 새로 배포받으세요. 그래도 안 되면 다른 네트워크(모바일 핫스팟 등)에서 시도합니다. 주소 앞의 http://와 포트 번호가 정확한지도 확인하세요.

벽 2. 소스를 봤는데 주석이 없다

원인: Elements 탭만 보고 Network의 원본 응답을 안 본 것일 수 있습니다. 프레임워크가 나중에 DOM을 바꾸면 처음 소스와 달라집니다.
해결: Ctrl+U(소스 보기)로 "서버가 보낸 그대로"를 보세요. JS 파일은 Sources 탭에서 하나씩 열고 Ctrl+Fflag, DH{, TODO를 검색합니다.

벽 3. 쿠키를 바꿨는데 변화가 없다

원인: 쿠키를 고친 뒤 페이지를 새로고침하지 않았거나, 서버가 쿠키를 검증하고(서명된 세션) 있거나, 값 형식이 틀렸습니다.
해결: ① Application 탭에서 값 변경 후 반드시 새로고침 ② Base64로 바꾼 값이면 다시 인코딩했는지 확인 ③ 그래도 안 되면 "서버가 검증한다"가 가설 — Step 150의 서명 개념으로 넘어가세요.

벽 4. 플래그를 찾았는데 제출하면 틀렸다고 나온다

원인: 앞뒤 공백이 같이 복사됐거나, DH{}가 빠졌거나, 비슷한 문자(0과 O, 1과 l)를 잘못 옮겼습니다.
해결: 플래그는 DH{로 시작해 }로 끝나는 통째 복사가 원칙입니다. 메모장에 붙여 공백을 확인한 뒤 제출하세요.

벽 5. 30분째 아무 단서도 못 찾았다

원인: 난이도를 높게 골랐거나, 아직 안 배운 기법의 문제일 수 있습니다.
해결: ① 문제 페이지의 힌트와 풀이 수를 보세요 — 풀이 수가 적으면 어려운 문제입니다 ② 난이도 1로 내려가세요 ③ 그래도 막히면 기록해 두고 다음 문제로. 실패도 Write-up의 재료입니다.


7. 정리

오늘의 개념

개념 한 줄 설명
CTF 플래그를 찾아 제출하는 해킹 문제 풀이 대회·연습 형식
플래그 서버에 숨겨진 정답 문자열 — 드림핵은 DH{...}
배포 서버 문제마다 발급되는 일회성 연습 서버 (만료됨)
풀이 사이클 정찰 → 가설 → 실험 → 플래그
Write-up 상황·시도·페이로드·배운 점을 적는 풀이 기록
화면 ⊂ 소스 화면은 서버 응답의 일부 — 소스 보기가 정찰의 기본

오늘의 명령어·도구

명령·도구 하는 일
Ctrl+U / Elements 탭 서버가 보낸 HTML 원본 읽기
Application 탭 → Cookies 쿠키 확인·수정
base64.b64decode("...") 쿠키 값 해독
/robots.txt 접속 숨겨진 경로 힌트 찾기
문제 페이지 서버 접속하기 일회성 연습 서버 발급

명령어보다 중요한 감각

실전 문제를 만나면 손을 멈추고 먼저 읽으세요. 난이도 1 문제의 플래그는 "공격해서 나오는 것"이 아니라 "철저히 읽으면 보이는 것"입니다. 그리고 기록은 미래의 나에게 보내는 편지입니다 — 오늘 푼 문제는 한 달 뒤의 내가 다시 못 풀 수 있습니다. Write-up 한 편이 그 재발을 막습니다. 마지막으로: 막히는 것은 실패가 아니라 다음 문제 선택의 정보입니다.


전부 체크되면 Step 151 완료입니다. 사이드바의 체크박스를 눌러 진도를 저장하세요.