NTLM (NT LAN Manager)
NTLM은 윈도우에서 제공하고 있는 인증 프로토콜 중 하나로 Challenge-Response(도전-응답) 라고 불리는 인증 프로토콜 방식을 사용한다. NTLM 은 사실 최근에는 거의 쓰이지 않고 있으며 MS 에서도 사용을 권장하지 않고있다. 다만, 아직 로컬 환경에서 쓰일 수 있으며 SMB 프로토콜에도 하위 호환성을 위해 내장되어 있다.
NTLM 인증 방식
NTLM 프로토콜은 크게 "Connection-Oriented(연결지향성)" 와 "Connectionless(비연결형)" 으로 나뉘지만 이번 포스팅에서는 연결지향성 NTLM만 다룬다. 두 방식은 큰 차이점은 없으며 NEGOTIATE 메시지를 먼저 보내는지 안보내는지 정도의 차이만 이해하고 있으면 될 것 같다.
- Challenge-Response 인증 프로토콜
NTLM이 Challenge-Response 프로토콜 방식으로 동작하기 때문에 NTLM 프로토콜을 시작하기전에 Challenge-Response 프로토콜에 대해 이해하고 있는 것이 좋다. Challenge-Response 프로토콜은 인증 프로토콜 중 하나로 다음과 같은 방식으로 키 값을 인증한다.
|
Challenge-Response 인증 프로토콜은 위와 같은 방식으로 동작하여 몇가지 변형이 있으나 큰틀은 바뀌지 않는다. NTLM 역시 위와 같은 방식으로 인증을 수행한다.
- NTLM 인증 흐름
NTLM 의 인증 흐름은 다음과 같다.
- 클라이언트 어플리케이션에서 세션인증이 필요하여 NEGOTIATE_MESSAGE 를 서버로 전송
- 이때 클라이언트가 인증과정에 필요한 각종 정보를 명세하여 전달 (Security feature)
- (클라이언트의 이름, 사용할 NTLM 버전, 해싱 방식 등) - 서버는 CHALLENGE_MESSAGE 를 클라이언트로 전송
- 클라이언트가 요청한 인증요소에 맞춰 서버가 생성한 임의의 Challenge(도전) 값을 포함하여 전달
- Challenge(도전)는 서버가 생성한 64Bit(8Byte) 의 의사난수 값 - 클라이언트는 AUTHENTICATE_MESSAGE 를 서버로 전송
- 유저의 암호를 기반으로 생성한 해시 값을 '응답' 값으로 포함하여 전달
- 'LM응답' 과 'NT응답' 이 전달됨 - 서버는 유저의 '응답' 이 유효한 값인지 확인후 인증완료
각 단계에서 보이는 NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE 는 NTLM 인증에서 사용하는 메시지 구조체이다.
- NTLM Message 구조체
- LM 해시와 NT 해시
상기의 NTLM 인증 흐름에서 봤듯이 NTLM 은 해싱된 유저 암호를 사용하여 인증 응답 값을 생성한다. 이때 사용되는 해싱방식은 LM 해시와 NT 해시 두가지가 사용된다. 두 방식은 NTLM 버전에 따라 내부적으로 구현되는 방식이 다르다. 두 해싱 방식의 차이는 다음과 같다.
NTLM 버전 | LM 해시 | NT 해시 | |
NTLMv1 | 해싱방식 | DES 방식 | MD4 방식 |
암호길이 | 14자까지만 가능 | 제한없음 | |
해시길이 | 128Bit(16Byte) | 128Bit(16Byte) | |
함수명 | LMOWFv1() | NTOWFv1() | |
NTLMv2 | 해싱방식 | NTLMv2 의 NT 해시와 동일 | HMAC-MD5 와 MD4 방식 |
암호길이 | NTLMv2 의 NT 해시와 동일 | 제한없음 | |
해시길이 | NTLMv2 의 NT 해시와 동일 | 128Bit(16Byte) | |
함수명 | LMOWFv2() | NTOWFv2() |
(LMOWF(), NTOWF() 에서 OWF 는 One Way Function 을 의미)
NTLMv1 에서 사용하는 LM 해시방식의 경우 구조상의 문제로 유저 암호를 14자까지만 사용 가능하다. 또한 NTLMv2 에서는 LM 해시와 NT 해시의 함수가 동일하다. 이는 NTLM 버전이 상승하면서 취약한 LM 해시 함수를 교체한 것으로 보인다.
- 해시함수 LMOWF(), NTOWF()
LM, NT 해시의 구현은 NTLM 버전에 따라 다르며 MS 에서 정의한 내용은 다음과 같다.
- LMOWFv1()
Define LMOWFv1(Passwd, User, UserDom) as ConcatenationOf( DES( UpperCase( Passwd)[0..6],"KGS!@#$%"), DES( UpperCase( Passwd)[7..13],"KGS!@#$%")) EndDefine * C = DES(K, D) C : 8Byte Message K : 7Byte Key D : 8Byte Data |
LMOWFv1() 은 14자리의 사용자 암호를 반으로 나눈 두 값을 각각의 DES key 로 사용한다. 따라서 LMOWFv1() 함수를 사용 할때 암호는 14자리를 넘을 수없다. 암호가 14자리 이하일 경우 빈 값은 널 값으로 처리된다. 또한 입력되는 암호를 모두 대문자로 치환하여 연산한다.
DES로 암호화는 값은 MS에서 지정한 임의의 고정 값이다("KGS!@#$%"). DES 로 암호화한 두 값을 이어 붙여 LMOWFv1() 의 해시 값으로 사용한다. 즉 최종해시 값은 16Byte 의 값이다.
- LMOWFv2()
NTOWFv2() 와 동일 |
NTLMv2 에서 사용되는 LMOWFv2() 함수는 함수와 내부적으로 NTOWFv2() 를 호출한다.
- NTOWFv1()
Define NTOWFv1(Passwd, User, UserDom) as MD4(UNICODE(Passwd)) EndDefine |
NTOWFv1() 은 MD4 해시를 사용하여 16Byte 의 해시 값을 생성한다.
- NTOWFv2()
Define NTOWFv2(Passwd, User, UserDom) as HMAC_MD5( MD4(UNICODE(Passwd)), UNICODE(ConcatenationOf( Uppercase(User), UserDom ) ) ) EndDefine |
NTOWFv1() 는 MD5 를 사용하는 HMAC 방식을 사용한다. 이때 사용자 암호는 MD4 로 해시화 되어 사용된다. 또한 유저 이름과 도메인명이 메시지로 사용된다. 출력값은 16Byte 이다.
- NTLM 의 인증 키 계산 (Response 값 계산)
NTLM 에서는 연결형이든 비연결형이든 클라이언트 측에서 "Challenge(도전)" 에 대한 "Response(응답)" 을 계산하여 전달해야 한다. 서버는 클라이언트로부터 전달받은 응답값을 생성과 동일한 방식으로 검증해야 한다.
- NTLMv1 에서의 인증 키 계산 (* 괄호안의 숫자는 해당 데이터의 바이트 크기)
@ NEGOTIATE 메시지에서 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 셋팅되어 있을 경우
1. ServerChallenge(8) 값과 ClientChallenge(8) 값을 연결. (16Byte 의 난수 생성)
* ServerChallenge: 서버에서 생성한 8Byte Challenege 값
* ClientChallenge: 클라이언트에서 생성한 8Byte Challenege 값
2. 상기의 16Byte 난수 값에 MD5 해싱을 적용하여 만든 메시지를 0~7 번째 바이트만 취함. 해당 값을 'Data' 라 함
3. NTOWFv1() 함수를 사용하여 'ResponseKeyNT(16)' 를 구함
4. DESL(ResponseKeyNT, Data) 를 연산하여 'NtChallengeResponse(24)' 값으로 사용
* DESL(K, D) 는 24Byte 값을 반환. (K: 16Byte, D: 8Byte)
5. 클라이언트 Challenge 값(8) 과 16Byte 의 제로 패딩을 연결하여 'LmChallengeResponse(24)' 를 만듬.
@ NEGOTIATE 메시지에서 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 값이 셋팅되어 있지 않을 경우
1. NTOWFv1() 함수를 사용하여 'ResponseKeyNT(16)' 를 구함
2. DESL(ResponseKeyNT, ServerChallenge) 를 연산하여 'NtChallengeResponse(24)' 값으로 사용
@ NoLMResponseNTLMv1 값이 셋팅 되어 있을 경우 다음 과정을 진행
i) 'LmChallengeResponse' 를 'NtChallengeResponse' 와 동일한 값으로 설정
@ NoLMResponseNTLMv1 값이 셋팅 되어 있지 않을 경우 다음 과정을 진행
i) LMOWFv1() 함수를 사용하여 'ResponseKeyLM(16)' 을 구함
ii) DESL(ResponseKeyLM, ServerChallenge) 를 연산하여 'LmChallengeResponse(24)' 값으로 사용
- NTLMv2 에서의 인증 키 계산
1. 다음 값들을 연결하여 'TempMsg' 를 만듬
- ResponseVersion(1) : 버전정보. 1로 셋팅
- HiResponseVersion(1) : 클라이언트가 알고있는 가장 높은 응답 버전. 1로 셋팅
- Zero(6) : 패딩
- Time(8) : GMT 시간
- ClientChallenge(8) : 클라이언트에서 생성한 Challenge 메시지
- Zero(4) : 패딩
- ServerName(가변) : NTLMv2_RESPONSE.NTLMv2_CLIENT_CHALLENGE.AvPairs 값 (서버이름)
- Zero(4) : 패딩
2. NTOWFv2() 함수를 사용하여 'ResponseKeyNT(16)' 을 구함
3. 'ServerChallenge(8)' 와 'TempMsg' 를 연결하여 'Data' 를 만듬
4. HMAC_MD5( ResponseKeyNT, Data ) 를 연산하여 'NTProofStr(16)' 값으로 사용
5. 'NTProofStr(16)' 값과 'TempMsg(가변)' 값을 연결하여 'NtChallegeResponse(가변)' 를 만듬
6. LMOWFv2() 함수를 사용하여 'ResponseKeyLM(16)' 을 구함
7. 'ServerChallenge(8)', 'ClientChallege(8)' 를 연결한 값을 'TempData' 라 함
8. HMAC_MD5( ResponseKeyLM, TempData ) 를 연산하여 'LmChallengeResponse(16)' 값으로 사용
[Linux] rsyslog 개념 및 사용법 - 로그 수집, 분석, 모니터링
[Algorithm] 위상 정렬 (Topological Sort)