Cross-Platform Rust Loader Delivers Modified Sliver Implant via Cloud Storage Abuse

by Will Seligman on Jul 20, 2026

RADICL threat intelligence report: Cross-platform Rust loader delivers modified Sliver implant via cloud storage abuse

 

We identified a two-stage malware operation: a Rust-compiled downloader that fetches and AES-128-CFB decrypts a second payload confirmed to be a modified build of Sliver, the open-source C2 framework. Both stages are staged inside a misconfigured cloud storage bucket belonging to an unrelated third party, and command-and-control runs behind Cloudflare Tunnel, concealing the operator's true origin server. RADICL tracks this activity as UNC-RAID-M8280.

Key Findings

  • A Rust-compiled loader downloads and AES-128-CFB decrypts a second-stage payload confirmed to be a modified build of Sliver, the open-source C2 framework.
  • One build pipeline covers five platforms — i386, ARM32, ARM64, and x86-64 Linux, plus Windows — with per-build AES keys patched into an otherwise-identical compiled template.
  • The Sliver payload carries a custom protobuf extension (FlyFireReq, FlyFireUpgradeReq, FlyFireToolsUploadReq) absent from the public Sliver source tree.
  • Both stages are staged inside a misconfigured cloud storage bucket belonging to an unrelated third party.
  • Command-and-control sits behind Cloudflare Tunnel, concealing the operator's true origin server. All observed C2 endpoints returned a tunnel-not-connected error at analysis time.
  • 31 unique objects recovered across four upload waves, June 2024 through June 2026.
00b_infection_chain

 

00_infrastructure_timeline

1. Loader

All loader samples are Rust binaries statically linking `reqwest`/`hyper`/`tokio` for HTTP, `aes`/`cfb-mode` for AES-128-CFB, and `rand_chacha`. Every build shares one binary template: a 32-byte block holding a 16-byte key followed by a 16-byte IV, immediately followed by a drop-path string. A patcher tool stamps new key/IV/path values into this block per build; same-wave builds across every architecture are byte-identical outside that one patched region.

Summary

Arch Samples Format Linking Entry Point Symbols Size
i386 3 (2 generations) ELF32 EXEC static 0x804be61 / 0x804bad5 stripped 1,381,524 / 1,444,352 B
ARM32 (EABI5) 3 ELF32 EXEC static 0x13f54 not stripped 1,832,272 B
ARM64 4 ELF64 EXEC static 0x4031bc stripped 2,016,000 B
x86-64 4 ELF64 DYN, static-PIE static, no NEEDED/INTERP 0x14c0a stripped 1,569,392 B
Windows 3 PE32+ GUI, MinGW-w64 static n/a stripped, no PDB 1,380,352 B

 

i386 — Two Build Generations

L-I386-1 (1,381,524 bytes, entry 0x804be61) predates the rest of the set by roughly two years. L-I386-2 and L-I386-3 (1,444,352 bytes, entry 0x804bad5) are from the 2026 waves and are byte-identical to each other outside the key/IV/path block. Different size and different entry point across the gap — a rebuild, not a re-key.

02_i386_build_generations_diff

 

All three are stripped. Key/IV recovered from the 32 bytes preceding each binary's embedded /tmp/ path:

  Key IV
L-I386-1 d0e2264dbad6c9a087a4c3bada926317 108e7e7b429f1d1eb188134a8af9601c
L-I386-2 5a912cc38d31d60b8578ae3368076fed dcedd5cbc3e07750f62cb79cec8e5252
L-I386-3 b5f233ba80dc1a3887d382a2ec929860 f242a50931193e5989c90eb833a60146

 

ARM32 — Unstripped, Confirms the Code Path Directly

All three ARM32 samples share one build (entry 0x13f54, 1,832,272 bytes) and, unlike every other architecture in this set, ship with symbols intact:

01_arm32_symbols_cfb_confirm

 

The key, IV, and drop-path string sit contiguous in memory, in that order:

10_key_layout_context

 

The source crate is named linux; control flow is can_access_internetdownloaddecrypt_shellcode_stub. Only an encrypt primitive exists in the binary — CFB decryption reuses the block cipher's encrypt operation on the keystream, so no separate decrypt routine is ever compiled in. The aes crate's soft::fixslice implementation is a bitsliced, table-free AES — it doesn't use the classic S-box lookup table, which is why that byte sequence doesn't appear anywhere in these binaries.

ARM64

Four samples, one build (entry 0x4031bc, 2,016,000 bytes). Symbols aren't retained here despite file reporting "not stripped" — key/IV extraction used the same drop-path-marker method as the stripped architectures.

x86-64

Four samples, one build (entry 0x14c0a, 1,569,392 bytes). file calls these "dynamically linked" — misleading. No NEEDED entries, no PT_INTERP segment: this is static-PIE, fully self-contained.

03_x64_static_pie_confirm

 

Windows — MinGW-w64

Three samples, 1,380,352 bytes, byte-identical outside a 270-byte patched window (offset 0xd2131–0xd223e) holding the same key/IV/path template, adapted to c:/users/public/downloads/<hex>.

Toolchain is GNU/MinGW-w64, not MSVC: MajorLinkerVersion=2.34 is a ld version number, no Rich/DanS marker is present anywhere in the file, and the import table pulls msvcrt.dll with legacy CRT startup symbols (__getmainargs, __initenv, _acmdln) characteristic of MinGW's crt1.o rather than MSVC's UCRT startup. Build timestamp 1751339644 (2025-07-01T03:14:04Z) is identical across all three.

192 imported functions across 14 DLLs. No CryptoAPI imports — AES-CFB is entirely the statically-linked Rust crates, same as the Linux builds. OpenProcess, VirtualAllocEx, WriteProcessMemory, ResumeThread, and CreateProcessA/W are all present, but NtUnmapViewOfSection and SetThreadContext/GetThreadContext are absent, as is CreateRemoteThread — the import table alone supports a drop-to-disk-and-execute loader, not confirmed process hollowing.

 

Cross-Architecture Notes

  • Key reuse spans architectures within a wave, not just within one architecture — the same AES key patches into the i386 build and the Windows build in the same batch.

  • No persistence, no mutex, no anti-debug or anti-VM strings anywhere in the loader, any architecture. Any persistence on a compromised host comes from the operator via the second stage, not the loader itself.

2. Payload

Decryption

All 13 second-stage payloads are AES-128-CFB ciphertext — no header, no magic bytes, uniform ~8.0 bits/byte entropy end to end. All 13 keys trace directly back to loaders in this set. Only nine distinct keys cover the 17 loaders, and the reuse isn't confined to one architecture — the same key can span multiple loader architectures and decrypt multiple payloads in different formats:

Key Loaders Sharing It Payloads It Decrypts
1 L-I386-1 P-ARM64-3
2 L-WIN-1, L-I386-3 P-I386-1, P-X64-1, P-X64-SC-3
3 L-WIN-3, L-I386-2, L-X64-4, L-ARM64-4 P-ARM32-2
4 L-WIN-2, L-X64-2 P-X64-SC-1
5 L-X64-1, L-ARM32-1 P-X64-SC-2
6 L-X64-3, L-ARM32-2 P-ARM32-1, P-ARM64-2
7 L-ARM32-3, L-ARM64-1 P-I386-2, P-X64-2
8 L-ARM64-2 P-I386-3, P-ARM64-1
9 L-ARM64-3 none recovered

 

Key 2 decrypts three payloads across three different formats — native i386, native x86-64, and x86-64 shellcode. Keys 6, 7, and 8 each decrypt two. The operator is minting one key per delivery batch, not per artifact — architecture and payload format don't factor into key assignment. Key 9's loader, L-ARM64-3, has no matching payload among the 13 recovered, meaning whatever it was paired with was never uploaded or already removed.

Identification

10 of 13 payloads decrypt to native ELF binaries matched to their loader's architecture. The remaining 3 decrypt to raw x86-64 shellcode with no file header — built for reflective/in-memory loading rather than execution from disk. Every payload, ELF or shellcode, carries the identical 198-message sliverpb.* capability surface — the shellcode packaging isn't a reduced build.

09_decryption_confirmed

 

Build fingerprint across all 13: Go 1.19.3, CGO_ENABLED=0, -trimpath=true (no leaked developer paths), module path github.com/bishopfox/sliver, version (devel).

11_sliver_identification

 

A Modified Fork

All 13 payloads carry protobuf message types compiled into the standard github.com/bishopfox/sliver/protobuf/sliverpb package that do not exist in the public Sliver source: FlyFireReq/FlyFireResp, FlyFireUpgradeReq (versioned self-upgrade, carries a file name and payload), and FlyFireToolsUploadReq/FlyFireToolsUploadResp (per-architecture tool upload with an MD5 checksum). Full getter methods are compiled in for every field — a genuine schema extension, not a stray string.

04_flyfire_custom_fork_evidence

 

Capability Surface

  • File system: Ls, Mkdir, Mv, Rm, Cd, Pwd, Download, Upload, FileInfo
  • Execution: Execute, ExecuteAssembly, InvokeExecuteAssemblyReq, InvokeInProcExecuteAssemblyReq, SpawnDll, Sideload, Task, Ps, ProcessDump, LinuxMemFdExecuteReq (fileless exec via memfd_create), WindowsMemExecuteReq
  • Privilege escalation: GetSystem, GetPrivs, Impersonate, MakeToken, RevToSelf, RunAs, CurrentTokenOwner, WindowsPrivilegeEntry
  • Persistence: Backdoor, ServiceInfo, StartServiceReq, StopServiceReq, Migrate
  • Windows registry: RegistryCreateKey, RegistryDeleteKey, RegistryRead, RegistryWrite, RegistrySubKeyList, RegistryValuesList
  • Networking and pivoting: Portfwd, RPortfwd, Socks, StartImplantLocalSocks5Req, WGSocks/WGSocksServer (WireGuard SOCKS), WGPortForward, WGTCPForwarder, NetConnPivot, Netstat, Ifconfig, Tunnel/TunnelData
  • Multi-hop pivoting: PivotHello, PivotListener, PivotPeer, PivotServerKeyExchange, PivotStartListenerReq
  • C2 session: BeaconRegister, BeaconTasks, DNSBlockHeader, DNSSessionInit, HTTPSessionInit, Envelope, OpenSession, Reconfigure, PollInterval, KillReq, WebhookTunnelData
  • Reconnaissance: Screenshot, EnvInfo, camera and interface enumeration via the vendored library set below
  • Extension framework: CallExtension, ListExtensions, RegisterExtension
  • Interactive access: Shell, SSHCommand
  • Fork additions: FlyFireReq/Resp, FlyFireUpgradeReq, FlyFireToolsUploadReq/Resp

Vendored Libraries

Library Capability
armon/go-socks5 SOCKS5 proxy backing the pivoting commands
hashicorp/yamux Session/tunnel stream multiplexing
fatedier/kcp-go KCP (reliable UDP) transport
Azure/go-ntlmssp NTLM authentication through corporate proxies
BurntSushi/xgb X11 screenshot/screen capture on Linux
gofrs/uuid Session/task/beacon identifiers
pion/stun, pion/dtls NAT traversal / pivoting transport

 

User-Agent Strings

13 unique UAs, one per binary, drawn from Sliver's default randomized pool — 11 Windows-shaped, 2 Linux-shaped, with synthetic Chrome version numbers that don't match real releases. Not tied to the binary's actual target platform.

C2 Domains

Domain Payloads
sim[.]lotteofficial[.]org 5 payloads (i386, x86-64 native, x86-64 shellcode ×2)
check[.]lotteofficial[.]org 3 payloads (ARM32, ARM64, i386)
demo[.]lotteofficial[.]org 2 payloads (i386, ARM32)
update[.]lotteofficial[.]org 2 payloads (ARM64, x86-64 shellcode)
update[.]traceroute[.]vip (https) 1 payload (ARM64, 2024 wave)

 

3. Infrastructure

Both stages are staged inside a misconfigured cloud storage bucket — an unrelated company's storage, not attacker-owned infrastructure, with anonymous list and read access enabled. The malware objects sit alongside years of that company's own operational data, giving the operation free, high-reputation hosting with no infrastructure footprint of its own. An unrelated Chinese-language scareware page (a Ministry of Public Security impersonation, hash LURE-1) was also present in the same bucket, with no functional connection to the loader/implant chain.

Command-and-control runs on a domain registered through NameCheap in December 2025, Cloudflare-fronted with certificates from Google Trust Services, plus one earlier domain (traceroute[.]vip) tied to the 2024 wave that had since lapsed into domain parking and finally NXDOMAIN. Both sit behind Cloudflare Tunnel — the operator's real origin server is never exposed via DNS or direct connection.

At the time of this analysis, every C2 subdomain returns Cloudflare error 1033 (tunnel not connected), reproduced through different methods.

Two additional subdomains on the same apex domain — api[.]lotteofficial[.]org and music[.]lotteofficial[.]org — were not observed in any recovered payload but return the identical Cloudflare Tunnel error, indicating shared operator infrastructure with no confirmed sample tying them to this campaign.

06_cloudflare_tunnel_error

 

One subdomain has a public historical scan (December 2025, status 200) serving a verbatim copy of the real systemd sysupdate.d manual page — cover content for anyone browsing the domain directly without the request signature an implant would send. Live reproduction returns the same tunnel error as everything else; the capture reflects a period when the tunnel was still connected.

Remediation

RADICL reported the abused storage bucket to the hosting cloud provider. The provider confirmed the reported content had been mitigated, removing the operator's staging and delivery point for both loader and payload stages.

4. Detection

Loader: a process writing a file to /tmp/<64–100 hex chars> (Linux) or c:\users\public\downloads\<64–100 hex chars> (Windows) and executing it shortly after is the strongest host indicator. Rust build-artifact strings (aes-0.7.5, cfb-mode-0.7.1, decrypt_shellcode_stub) survive stripping and are stable across build generations.

Payload: the FlyFire* protobuf strings are a low-collision signature for this specific fork if the payload is ever recovered unencrypted. memfd_create-based fileless execution (Linux) and unbacked executable memory regions (Windows) match the implant's compiled capabilities. Domain-based blocking of the C2 domains is more effective than IP-based blocking, given Cloudflare Tunnel's shared, rotating edge addresses.

Infrastructure: this delivery chain depends entirely on a cloud storage bucket with open list/read permissions.

Indicators of Compromise

Files

ID SHA-256 Size Role
L-WIN-1 15129930ccc8ce4d51fe4d4a3a870cc5d236e51dd0d631b8f7034d892091811d 1,380,352 Loader (Windows)
L-WIN-2 45e43d5dab0436a84a15fea3a87fd6d4356c0e6e1b9093118551877d100bec18 1,380,352 Loader (Windows)
L-WIN-3 e752a754500947fe040cd15118e25e0a47fb58f98c25df716415be6f218159ac 1,380,352 Loader (Windows)
L-I386-1 ec188c14a8498774610961557ad1e911b0b6471eb144d0dab22fc4fedb66aa06 1,381,524 Loader (i386)
L-I386-3 e21448d9cf4baf67036aa42569add5e1d61ed99187b84fe38b41d6229ca7bf58 1,444,352 Loader (i386)
L-I386-2 a87e19e5a069d37d440f929c7598df4f610e82f741aec448d88c5dcfbae610c0 1,444,352 Loader (i386)
L-X64-1 8146f23ceb065296376da9b43cb2f4e1744ccf7dc498482f30601bbc1ebc92fe 1,569,392 Loader (x86-64)
L-X64-2 0ba7c5966efb4babb60f74cd4c6905c0f5396ad681933d5f7eec9476e520d4e3 1,569,392 Loader (x86-64)
L-X64-4 e470aac5a5a2dc9c85d43d5b4c91eaa0c7ee17ea069c4f9d64bccfd084a0eba7 1,569,392 Loader (x86-64)
L-X64-3 89d6582190f2e3e1974081c7b724145316c4ed096977667f5d9c22dab687bee1 1,569,392 Loader (x86-64)
L-ARM32-1 68cc6d10e471684dc12854dbcde358a79ba75196a8a8483e18c95a38b7570799 1,832,272 Loader (ARM32)
L-ARM32-2 93144e0ad2c9d7be4835b186c9c66249315e4eea578208db09d538dc9c3bfd36 1,832,272 Loader (ARM32)
L-ARM32-3 0ff5dcc2e16fd793a5be3608d7b8b42101496ee017c381975a6ed05bb326dc49 1,832,272 Loader (ARM32)
L-ARM64-1 6f1f689f7142a20aeee707234f177733cc49030a3be3f7a7b6aa3da3c20e1f6e 2,016,000 Loader (ARM64)
L-ARM64-2 0f4e170f68f756a478885aae2b1bbb98a79cbae21fcb9d5c0a6d90aac1940877 2,016,000 Loader (ARM64)
L-ARM64-3 200ac78f7a62ca33ad81a00e56106046363a8c2d702ff0248a01c1d2c0d29d8c 2,016,000 Loader (ARM64)
L-ARM64-4 094ab5c4eca64bbe80a1fb242de9f49a4f9246b029754d0d9049fe6bcf8ad280 2,016,000 Loader (ARM64)
P-ARM32-1 e93e236ec56f2eff761bd7ef5ebc073e107905cf10978bdb106688e2a7f83158 10,682,368 Payload — ARM32
P-ARM32-2 1a2beac30028a2368f7af0893e86a015cebce9d5644bb787b18fce10f4b025c4 10,682,368 Payload — ARM32
P-I386-1 91c584b2897a59960f22bcb2391a25ab5a4fd498a76f08c7a3c8428922eed929 10,694,656 Payload — i386
P-I386-2 dadad7a7524979a5688287aa6e1fa0e0476606db5e1a4148a8cfff07e05831bf 10,694,656 Payload — i386
P-I386-3 29a8c39617ef25bffeb7925a11d08ed550ace3dde3df571388c78b12662a7e94 10,694,656 Payload — i386
P-ARM64-1 de78c0bd5a1cad3c69aca691e29ae10a31d83bb95cf8dd06b47dd733222c6519 10,747,904 Payload — ARM64
P-ARM64-2 7940d87bb7e413a3f0a20c90a86f973ca7174e04c3c7d1b71c9d5c7043dcb8ea 10,747,904 Payload — ARM64
P-ARM64-3 f507437b764a73e819641443a946e0b252e0d46ac029189615f67b348c97401f 10,747,904 Payload — ARM64
P-X64-1 56c7dbafefafb3d7b8927aab4bdcea528ab5380d59e51b3ca28a7301d13eb445 11,493,376 Payload — x86-64
P-X64-2 76d2e41a6d0efc2eb895d61477ff60f957722d5af42265957e54a70feaf00678 11,493,376 Payload — x86-64
P-X64-SC-1 5b734ddfab4e87d0805f5d2b76a2ba0b9da3e413837539da9c53d33cc6dc018c 11,746,524 Payload — x86-64 shellcode
P-X64-SC-2 5de704b2c88a2c56ab9db3b02d029ff52c7b1cb16e3190aa3fc7d9103a6e2522 11,746,524 Payload — x86-64 shellcode
P-X64-SC-3 055ba3a7328613e5a162a6e38f0758fcd7faae06786f4e8d955d2be1432ff8fb 11,747,036 Payload — x86-64 shellcode
LURE-1 a3ec88293cfbd0be4c8331a4397e12f8a97067073bec94d6666eb69519d9ea6e 4,624 Scareware HTML lure

 

Network

Indicator Type
sim[.]lotteofficial[.]org C2
check[.]lotteofficial[.]org C2
demo[.]lotteofficial[.]org C2
update[.]lotteofficial[.]org C2
update[.]traceroute[.]vip C2
api[.]lotteofficial[.]org C2 (no payload observed)
music[.]lotteofficial[.]org C2 (no payload observed)

 

File System

Pattern OS
/tmp/[0-9a-f]{64,100} Linux drop path
c:\users\public\downloads\[0-9a-f]{64,100} Windows drop path

 

YARA

rule Rust_Stager_AES_CFB_Sliver_Loader {
    meta:
        description = "Rust-compiled multi-platform stager that downloads and AES-CFB decrypts a Sliver-family implant"
        date = "2026-07-09"
    strings:
        $sym1 = "linux::download" ascii
        $sym2 = "decrypt_shellcode_stub" ascii
        $sym3 = "can_access_internet" ascii
        $crate_aes = "aes-0.7.5" ascii
        $crate_cfb = "cfb-mode-0.7.1" ascii
        $droppath_lin = /\/tmp\/[0-9a-f]{60,100}/ ascii
        $droppath_win = "c:/users/public/downloads/" ascii nocase
    condition:
        (2 of ($sym*)) or (all of ($crate_aes, $crate_cfb)) or $droppath_lin or $droppath_win
}

rule Sliver_Implant_Custom_FlyFire_Extension {
    meta:
        description = "Sliver C2 implant carrying non-stock FlyFire* protobuf extension"
        date = "2026-07-09"
    strings:
        $stock1 = "github.com/bishopfox/sliver" ascii
        $stock2 = "sliverpb." ascii
        $custom1 = "FlyFireReq" ascii
        $custom2 = "FlyFireUpgradeReq" ascii
        $custom3 = "FlyFireToolsUploadReq" ascii
    condition:
        (1 of ($stock*)) and (1 of ($custom*))
}

 

Get Email Notifications

No Comments Yet

Let us know what you think