SignalRGB: standard user to SYSTEM, by way of a service binary anyone can overwrite
Whoso breaketh an hedge, a serpent shall bite him.
Ecclesiastes 10:8 (KJV)
same well i went down for SteelSeries GG: RGB software, the kind everyone installs and nobody audits, running a service as the most privileged account on the box because it needs to poke hardware. SignalRGB was already on the bench for a driver bug, so while it was sitting there installed i ran the boring pass i run on anything that ships a service, list the services, see which ones are SYSTEM, then go look at where their binaries actually live and who's allowed to write them. most days that's a dead end. this time it was the whole finding, first service on the list.
Name : SignalRgb.Service
StartName : LocalSystem
StartMode : Auto
PathName : "C:\Users\exp\AppData\Local\WhirlwindFX\SignalRgb\service\SignalRgbService.exe"
a service that runs as LocalSystem, starts on its own at boot, and whose executable
sits inside a per-user AppData\Local folder. the path alone is a bad
smell, because profile directories belong to the user, not to SYSTEM. so the only
question left is the ACL on that file.
# icacls ...\service\SignalRgbService.exe
NT AUTHORITY\SYSTEM:(I)(F)
BUILTIN\Administrators:(I)(F)
WIN-EXP\exp:(I)(F)
WIN-EXP\noob:(I)(F) # a plain standard user. Full Control.
that's the bug, all of it, in one line. noob is a standard user with no
groups and no admin, and it holds Full Control over the executable of a service that
runs as SYSTEM. the installer dropped a SYSTEM binary into a user-owned directory and
then granted every user write access to it. you don't need a memory corruption or a
race or a clever primitive. you need copy.
the swap
the one real obstacle is that the running image is locked against an in-place write. that stops less than it sounds like. Windows is perfectly happy to let you rename a running executable, it only protects the bytes the loaded image came from, not the directory entry pointing at them. move the real binary aside, drop your own in the name it left behind. the file sits under another user's profile, but Bypass-Traverse-Checking is handed to Everyone by default, so a standard user reaches it by full path without any right to the folders above it.
whoami: win-exp\noob
rename: 1 file(s) moved. # SignalRgbService.exe -> .bak
copy: 1 file(s) copied. # our payload -> SignalRgbService.exe
dir: 06/15/2026 05:43 AM 14,848 SignalRgbService.exe
the service binary is ours now. fourteen kilobytes where twelve megabytes used to sit, waiting for the next start.
the trigger, honestly
this is the part writeups like to skip, so here it is plainly. the service control DACL
grants Users RP, which is SERVICE_START, but not stop. and you can't
taskkill it, it runs as SYSTEM. so a standard user can start the service but cannot
restart one that's already running, and in normal operation it's running. that leaves
two honest triggers, and i'm not going to pretend there's a third.
the clean one is a reboot. the service is Auto-start, so on the next boot the service manager runs our planted binary as SYSTEM, and a standard user is allowed to reboot. that's the whole thing if you can wait for a restart or a logoff.
the no-reboot one is a chain, and it leans on the box already being soft elsewhere.
this machine also ran SteelSeries GG, whose
update proxy service is demand-start and startable by any user, i already had a SYSTEM
sideload into it. i used that to borrow SYSTEM just long enough to stop and start
SignalRgb.Service. here's the shortcut worth saying out loud, because it's the part
that makes the chain cheap: the moment anything restarts the service through a stop, it
lands in the stopped state, and from there noob's own SERVICE_START fires the
planted binary directly. borrow SYSTEM once to knock it loose; every pop after that is
a one-liner.
the pop
the payload is the ordinary service-launched move. SCM starts it as SYSTEM in session 0, so it duplicates its own token into the active console session and spawns a cmd.exe on the interactive desktop. a quieter build skips the window and just adds you to Administrators. i ran both.
# Administrators, after
Administrator
exp
noob # standard user, now a local admin
# cmd.exe: pid / session / user
PID Session# User Name
5416 1 NT AUTHORITY\SYSTEM # a SYSTEM shell, on noob's own desktop
two separate SYSTEM executions, both stamped nt authority\system, ending with
a standard user in the Administrators group and a SYSTEM prompt sitting on their own
console. the dropper and the payload are about a hundred lines of C between them. one
finds the service binary under any profile, renames the real one to .bak,
drops the payload, and calls sc start. the other is the token-to-session
spawn. nothing in either is clever. the cleverness was all in the installer, which ran
as admin for one moment, and used that moment to hand the keys back to the tenant.
CWE-732 and CWE-276 wearing one coat: a per-user install directory is the wrong home
for anything that runs as SYSTEM, and stacking Users:Full-Control on top turns the wrong
home into a free one. if the binary has to live in a writable tree, it has to be ACL'd
down to SYSTEM and Administrators, and the service ought to verify it before it launches.
none of that held here.
. _SiCk · 0xdeadbeefnetwork · afflicted.sh