도메인 컨트롤러 데이터베이스 (NTDS.DIT) 공격
목차:
그래서, 제가 약속한 대로, 이전에 설명된 공격의 개별 Cyber Kill Chain 단계 분석을 시작합니다. 오늘 우리는 회사 인프라에 대한 공격 벡터 중 하나를 검토할 것이며, 이는 두 단계로 간주될 수 있습니다: ‘목표에 대한 행동’ 및 ‘정찰’. 우리의 목표는:
- 획득한 계정을 사용하여 발판을 마련하는 것;
- 회사에 대한 최대 정보를 얻는 것(이메일, 부서 이름, 전화번호, 직무 제목 등)으로, 이후의 공격 또는 그 인프라 액세스 판매를 위한 것입니다.
SYSTEM 및 NTDS.DIT
적들이 기업 네트워크에 침입하면, ActiveDirectory의 ‘가장 중요한’ 정보 중 하나인 SYSTEM 및 NTDS.DIT 파일에 접근하려 할 것입니다. 이 파일들은 ActiveDirectory의 모든 데이터를 포함한 데이터베이스입니다. NTDS.DIT는 도메인 내 모든 사용자에 대한 정보와 비밀번호 해시를 포함합니다. SYSTEM 파일은 NTDS.DIT의 데이터를 해독하는 데 필요합니다.
해시를 가져오는 방법은 이 글에서 설명하지 않겠습니다. 관련 주제에 대한 글이 이미 많이 작성되었기 때문입니다. 저는 인프라 취약성을 비밀번호 공개 위험으로 보여주는 방법과 검색 과정을 자동화하여 극도로 빠르게 만드는 방법에 집중할 것입니다.
따라서 우리는 오직 LM 및 NTLM 해시만 필요합니다:해시를 수신한 후 LM 해시로 시작합니다.
LM 해시 관련 정보
LM 해시에 관한 정보.
이는 DES 블록 암호 에 기반하고, 실현에 두 개의 취약점이 있어 비밀번호를 깨뜨리는 데 쉽게 공격할 수 있습니다. 첫째로, 7자보다 긴 비밀번호는 두 부분으로 나뉘고 각 부분이 개별적으로 해시되므로 각각의 부분을 개별적으로 공격할 수 있습니다. 둘째로, 모든 소문자가 대문자로 전환됩니다.
따라서 우리는 다음과 같습니다:
LM 해시는, 이전에 알아본 대로, 두 부분으로 구성되어 있습니다.9196B21FEF3C8906AAD3B435B51404EE
AAD3B435B51404EE – 이 해시는 빈 비밀번호에서 온 것 입니다 (이러한 숫자 배열은 해시의 한 절반이 빈 비밀번호라는 것을 의미합니다).
우리는 비밀번호가 7자 미만이라는 결론을 내립니다, 왜냐하면 해시의 두 번째 부분이 빈 문자 집합과 일치하기 때문입니다.
이제 첫 번째 부분을 무차별 대입할 차례입니다
그 목적을 위해 우리는 hashcat, 을 사용하여 강력한 병렬화된 GPU 무차별 대입 합니다. 다음 키를 사용합니다:
-a => 공격 모드
-m => 해시 유형
?d = 모든 숫자 (0–9).
?l = 소문자 (a–z).
?u = 대문자 (A–Z).
?s = 기호.
비밀번호를 24초 만에 받습니다.
이제 NTLM의 차례입니다
1BC10704ED604747D7D827FC7A43D555
그것을 무차별 대입하는 것이 훨씬 더 쉽습니다, 왜냐하면 다음 정보를 알고 있기 때문입니다:
- 비밀번호에 사용되는 문자;
- 이 문자들의 순서.
우리는 단지 문자가 대문자인지 소문자인지를 확인하기만 하면 됩니다.
그러므로 LM 해시가 있기 때문에 모든 작업은 약간 넘는 32초 만에 완료되었습니다.
우리는 작업을 더 복잡하게 만들 것입니다:
14자의 비밀번호를 가지고 세 번째 난이도 수준(고전적인 회사 비밀번호)이라고 가정해 봅시다:29355BC0D45C341B51ACD8D3923F7C21
우리는 동일한 요령을 사용합니다:무차별 대입은 31초 만에 첫 번째 근사값(대문자로 된 비밀번호)를 줍니다.
29355BC0D45C341B51ACD8D3923F7C21
이제 우리가 해야 할 일은
NTLM:E06E777CD11F495E9B9098B5576A4343
비밀번호의 복잡성을 14자까지 늘리더라도 우리의 작업은 더 어려워지지 않습니다 – LM 해시가 있으면 깨뜨리는 데 40초 밖에 걸리지 않습니다!우리는 하나의 해시를 처리했습니다. 많은 양의 해시를 처리해야 한다면, 각각의 비밀번호에 대해 마스크를 만드는 것은 너무나도 노동집약적입니다. 그래서 저는 우리를 위해 다음 작업을 수행할 도구를 개발했습니다 – ntlm_mask_gen.exe
(여기에서 다운로드할 수 있습니다 여기, MD5: c2a9dac79c51e14c84f35febd72d05ba
또는 부록 1) :
- 각각의 비밀번호에 대해 워드리스트를 형성합니다;
- 형성된 워드리스트를 포함한 각각의 비밀번호에 대해 마스크를 형성합니다;
- 각각의 별도 해시, 마스크 및 워드리스트에 대한 문자열을 포함한 하나의 파일을 만듭니다.
그러고 나면 그 파일을 실행하고 hashcat 몇 초 만에 비밀번호가 깨지는 것을 지켜보세요.
설명한 방법론 시연
설명한 기술을 시연하기 위해 또 하나의 실험을 수행해봅시다.
다음 설정(기업 비밀번호 정책의 기술/행정/시스템 계정의 전통적 요구 사항)으로 난이도 4단계 10자로 구성된 10개의 비밀번호를 사용할 것입니다:
- 우리는 해시가 포함된 파일을 만듭니다
csv
:
- 그런 다음 도구를 위한 파일을 생성합니다, 이는 우리를 위해 워드리스트와 마스크를 생성할 것입니다. NTLM 해시와 LM를 해킹하기 위한 비밀번호를 예로 들어
test_ntlm_input.txt
:
- 그 파일을 실행하고 14초 만에 비밀번호를 얻습니다:
명확화
잘 아시다시피, 버전 2008부터 LM 해시 저장은 기본적으로 비활성화 되지만, 버전 2003(또는 이하)에서 마이그레이션된 경우, 마이그레이션 후 비밀번호를 변경하지 않은 계정은 데이터베이스에 LM 해시가 남아 있습니다. 보통 이러한 계정은 비밀번호가 여러 이유로 변경되지 않는 기술 계정이며, 예를 들어 일부 중요한 서비스의 충돌을 일으킬 수 있기 때문입니다. 이러한 계정은 ‘만료되지 않음’ 비밀번호를 가지며, 그들의 액세스는 모니터링되지 않으며 종종 관리자 액세스에 이르기까지 높은 권한을 가집니다. 따라서 이러한 계정을 통한 침입은 가장 은밀할 것입니다.
결론
2003 이하 기반의 도메인을 포기하고 최신 버전을 사용하는 것이 중요합니다. 마이그레이션의 경우 모든 계정이 비밀번호를 변경했음을 보장하고 데이터베이스에 LM 해시가 없도록 해야 합니다. 그리고 도메인 관리자와 정보 보안 전문가에게 더 하나의 조언입니다, 적극적으로 작업을 하고 최소한 분기별로 한 번씩 비밀번호를 무차별 대입 해야 합니다! AD에 대한 접근을 특히 SYSTEM 및 NTDS.DIT 파일과의 작동을 감시하며 통제해야 합니다.
이 글이 정보 보안 전문가들에게 유용하기를 바랍니다, 이들이 IT 전문가들과 소통할 때 설명한 기술을 논거로 사용할 수 있습니다. 아니면 ActiveDirectory 공격 관련 위험을 더 넓게 이해하려는 관리자를 위해 유용할 것입니다.
부록 1
import math 알파벳 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'예외 = ' &%{}&^|"'파일명 = 열기('D:hashcatkd_input.new','r')main_len = len(파일명.readlines())파일명.닫기()파일명 = 열기('D:hashcatkd_input.new','r')file_name_out = 열기('D:hashcatkd_input.cmd','w')해시 = []비밀번호 = []마스크 = [[] for i in 범위(main_len)]사전 = []char_sets_count = 0문자 세트 = [[] for i in 범위(main_len)]ind_main = 0 ch1 = [] ch2 = [] ch3 = [] ch4 = []ch_sets = [ch1, ch2, ch3, ch4] def new_init(통과_문자): for ind_0 in 범위(4):ch_sets[ind_0] = [] 반환 예측(통과_문자) def 예측(새로운_비밀번호):통과_문자 = '' for let in 새로운_비밀번호: if let in 알파벳 and not (let in 통과_문자):통과_문자 += let 반환 사전_생성기(통과_문자) def 사전_생성기(통과_문자): 글로벌 char_sets_count dict_new = ''pass_len = len(통과_문자) if pass_len < 4: for ind1 in 범위(pass_len):ch_sets[ind1].첨부(통과_문자[ind1])ch_sets[ind1].첨부(통과_문자[ind1].소문자()) 그 외:충전기(통과_문자, 확산기(pass_len)) for ind2 in 범위(4): if len(ch_sets[ind2]) > 0:dict_new += '-' + str(ind2+1) + ' ' + ''.결합(ch_sets[ind2]) + ' '문자 세트[char_sets_count] = [ch_sets[0], ch_sets[1], ch_sets[2], ch_sets[3]]char_sets_count += 1 반환 dict_newdef 확산기(문자_번호):spread_counter = [0, 0, 0, 0] for ind3 in 범위(4):spread_counter[ind3] = int(수학.ceil(문자_번호/플로트(4-ind3)))문자_번호 -= spread_counter[ind3] 반환 spread_counterdef 충전기(통과_문자, 카운터_문자):count_l = 0 for ind_ch in 범위(4): for ind_set in 범위(카운터_문자[ind_ch]):ch_sets[ind_ch].첨부(통과_문자[count_l])ch_sets[ind_ch].첨부(통과_문자[count_l].소문자())count_l += 1 def 마스크_생성기(비밀번호,pwd_idx):새로운_마스크 = '' for pw_let in 비밀번호: if pw_let in 알파벳: for ind_array in 범위(4): if pw_let in 문자 세트[pwd_idx][ind_array]:새로운_마스크 += '?'+str(ind_array+1) elif pw_let in 예외:새로운_마스크 += '?s' 그 외:새로운_마스크 += pw_let 마스크[pwd_idx] = 새로운_마스크# ---------------------- 메인 -------------------------------- for 라인 in 파일명:해시.첨부(라인[:32])비밀번호.첨부(라인[33:len(라인)-1])사전.첨부(new_init(비밀번호[ind_main]))ind_main += 1 for pwd_idx in 범위(len(비밀번호)):마스크_생성기(비밀번호[pwd_idx],pwd_idx) for 인덱스 in 범위(len(해시)):텍스트 = 'cudaHashcat64.exe -m 1000 -a 3 -o ntlm_tesult.hash ' + str(해시[인덱스]) + ' ' + str(사전[인덱스]) + ' ' + str(마스크[인덱스]) + 'n'file_name_out.쓰기(텍스트)파일명.닫기()file_name_out.닫기()