# The Silent Recon - Why Malware Authors Choose RID Cycling

When an attacker lands a foothold on a Windows machine, their absolute first priority is discovery. They need to answer one crucial question: Who else is on this box?

Finding local accounts—especially local administrators—is pure gold for an adversary. If a local admin account shares a username and password across multiple systems, that single misconfiguration lets an attacker pivot from one compromised machine to the entire network in minutes.

But *how* an attacker finds these accounts makes all the difference between triggering alarms or slipping by completely unnoticed.

* * *

## The Loud Way: Why `net user` Gets You Caught

If you look up how to list users on Windows, you’ll usually find these common methods:

1.  The Old WAY OF Command Line: Running `net user` or `net localgroup administrators`.
    
2.  PowerShell / .NET / ADSI: Running commands like `Get-LocalUser`.
    
3.  WMI Queries: Using `wmic useraccount list brief`.
    

## Why Security Tools Trap This Instantly

Modern Endpoint Detection and Response (EDR) software acts like a hyper-alert security guard watching the command line.

The moment a non-standard background process (like an exploited app or a malicious document) suddenly spawns `cmd.exe /c net user`, the EDR flags it immediately. Security teams have written strict rules specifically to trigger alerts whenever these exact command-line footprints show up in the logs.

Because these standard tools leave an obvious trail, smart malware authors completely avoid them. Instead, they use a technique that creates zero new processes and leaves no command-line footprints: RID Cycling.

![](https://cdn.hashnode.com/uploads/covers/69441e0da418bf1fc22446c0/c19daab7-3735-46b9-b9c9-b623f76f76ea.png align="center")

*The same discovery goal, two very different footprints — and exactly what EDR records for each path.*

* * *

## Understanding SIDs and RIDs

To understand how RID cycling works, we first need to look at how Windows actually handles identities. In the eyes of Windows, absolutely everything—each user, computer, group, and even the domain itself—is treated as an object. And every single object gets its own unique digital ID card called a SID (Security Identifier).

A SID string is split into two primary parts: the Base SID (which identifies the authority/source) and the RID (Relative Identifier) (the unique sequential number at the very end).

![](https://cdn.hashnode.com/uploads/covers/69441e0da418bf1fc22446c0/715e89e2-01c4-4c6f-a703-64a893286e0f.png align="center")

*One SID, taken apart: the Base SID stays fixed while only the RID at the tail changes from account to account.*

A common point of confusion is how a machine tracks its own identity when it joins a network. The truth is, a domain-joined computer actually manages two completely separate identities running side-by-side:

## The Blueprint of Windows IDs

*   The Machine Identity:
    
    *   Before joining a domain: The computer uses its own randomly generated Machine SID.
        
    *   While joining a domain: Active Directory hands it a brand-new identity built as `[Domain SID] + [Machine RID]`.
        
    *   *The Secret:* The machine never merges these. It keeps both.
        
*   User Identities:
    
    *   Local User: Built using `[Original Machine SID] + [User RID]`. (It completely ignores the domain).
        
    *   Domain User: Built using `[Domain SID] + [User RID]`.
        
*   Group Identities:
    
    *   Local Group (Custom): Built using `[Original Machine SID] + [Group RID]`.
        
    *   Domain Group: Built using `[Domain SID] + [Group RID]`.
        

![](https://cdn.hashnode.com/uploads/covers/69441e0da418bf1fc22446c0/261508a8-ffe5-4467-b6a3-0e01d31732ee.png align="center")

*Two worlds of identity. Every object is simply its authority’s SID plus a RID — only the authority (LOCAL vs DOMAIN) changes.*

## Wait, Where is that Domain Computer SID Actually Used?

If the machine keeps that `[Domain SID] + [Computer RID]` identity, where does it use it? Think of it as a Corporate Employee ID Badge.

During system boot, way before the login screen appears and before any human enters a password, `lsass.exe` starts up. The computer logs into the Domain Controller using its hidden machine account password. It flashes its Domain Computer SID to prove it is a legitimate corporate asset. This lets it pull down Group Policies and safely communicate server-to-server over the network.

![](https://cdn.hashnode.com/uploads/covers/69441e0da418bf1fc22446c0/51533c5c-d35a-49d7-95c5-326f09cb088e.png align="center")

*The machine’s domain identity is a boot-time corporate badge — and it never touches the local Machine SID that RID cycling abuses.*

* * *

## Test It Yourself: Checking Machine's SIDs

You can see this identity mapping in action right now using a standard Command Prompt (`cmd.exe`):

1.  View your current user account's SID:
    
    ```cmd
    whoami /user
    ```
    
    *Look at the output. The long middle part is your unique Machine SID, and the very last number (like* `-1001`*) is your User RID.*
    
2.  View your local groups:
    
    ```cmd
    whoami /groups
    ```
    
    *You might notice groups like* `BUILTIN\Administrators` *look like* `S-1-5-32-544`*. They don't use your Machine SID because they are Built-in System Groups. Windows hardcodes these globally with a generic prefix (*`S-1-5-32`*) so they are the same on every PC in the world.*
    

![](https://cdn.hashnode.com/uploads/covers/69441e0da418bf1fc22446c0/6cbc3097-bc27-41bb-addc-6be6b78a0d0e.png align="center")

1.  Prove the rule (Create a Custom Group):  
    If you run an elevated Command Prompt and create a *custom* group, Windows will immediately fall back to your unique Machine SID:
    
    ```cmd
    net localgroup MyTestGroup /add
    powershell -Command "Get-LocalGroup -Name MyTestGroup | Select-Object Name, SID"
    ```
    
    *Output:* `MyTestGroup S-1-5-21-[Your-Machine-SID]-1002`
    

![](https://cdn.hashnode.com/uploads/covers/69441e0da418bf1fc22446c0/768244bc-19cd-4d67-9174-7540fcdf17f1.png align="center")

## The Guessing Game: How RID Cycling Works

Now that we have the mental model down, RID cycling is easy to understand.

Instead of knocking on the front desk and asking for a full list of all employees (which security will flag as suspicious), an attacker walks up to an automated intercom and manually dials extensions one by one: `1001`, `1002`, `1003`. If a name pops up, they write it down. If it says "Invalid," they skip it.

An attacker throws this logic into an automated loop:

1.  Grab the Base Machine SID: They grab the local computer's unique Machine SID (which they can easily read from basic registry paths like `ProfileList`).
    
2.  Build the Guess List: They programmatically append sequential RIDs to the end of that Machine SID.
    
    *   They start with well-known ones: `Machine-SID-500` (Always the built-in Administrator).
        
    *   Then they cycle through user space: `Machine-SID-1000`, `Machine-SID-1001`, `Machine-SID-1002`...
        
3.  Ask for a Translation: For every SID they generate, they call a standard Windows utility function: `LookupAccountSid`.
    

Windows looks at the generated SID and answers: *"Oh, that ID belongs to a user named* `Veera`*."* If the RID doesn't exist, Windows just returns an error, and the script moves to the next number.

![](https://cdn.hashnode.com/uploads/covers/69441e0da418bf1fc22446c0/5ae6d484-8f44-42dd-8221-10059db58b47.png align="center")

*The loop in one picture: hold the Base SID fixed, walk each RID, and let Windows translate the ones that exist.*

```powershell
# Step 1: Extract the local Machine SID directly from the ProfileList registry key
# We find any subkey starting with 'S-1-5-21-', pick the first one, and strip off the final user RID.

$RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
$UserSIDSubkey = (Get-ChildItem $RegPath | Where-Object { $_.PSChildName -like "S-1-5-21-*" } | Select-Object -First 1).PSChildName

if (-not $UserSIDSubkey) {
    Write-Error "[-] Could not find any local user SIDs in the ProfileList registry path."
    exit
}

$MachineSID = $UserSIDSubkey -replace '-[0-9]+$', ''
Write-Host "[+] Discovered Local Machine SID via Registry: $MachineSID" -ForegroundColor Green
Write-Host "[+] Starting RID Cycling loop..." -ForegroundColor Cyan
Write-Host "--------------------------------------------------"

# Step 2: Define the RIDs we want to test

# 500 = Admin, 501 = Guest, 1000+ = Custom Users
$RIDsToTest = @(500, 501) + (1000..1050)

# Step 3: Run the translation loop

foreach ($RID in $RIDsToTest) {
    # Construct the full target SID string
    $TargetSIDString = "$MachineSID-$RID"

    try {
        # Call the underlying Windows translation engine (LookupAccountSid equivalent)
        $SIDObject = New-Object System.Security.Principal.SecurityIdentifier($TargetSIDString)
        $Account = $SIDObject.Translate([System.Security.Principal.NTAccount])     
        # If it successfully translates, print out the account name
        Write-Host "[FOUND] RID $RID -> $($Account.Value)" -ForegroundColor Yellow
    }
    catch {
        # If the RID doesn't exist on the system, Windows throws an error. We silently skip it.
        continue
    }
}
```

![](https://cdn.hashnode.com/uploads/covers/69441e0da418bf1fc22446c0/440f93a9-db9a-4e9e-9a99-2c1e05ab0924.png align="center")

### Why This Completely Evades EDR

This technique turns a dangerous **search** problem into an innocent **translation** problem, completely blinding security filters.

1.  **Registry Reads are Too Noisy to Log**  
    The `ProfileList` registry key is read constantly by legitimate applications to check user paths. Because EDR tools focus heavily on registry **writes** (to prevent malware persistence), logging every simple read operation of a standard system key would generate millions of useless logs and crush system performance. Security tools deliberately skip this background noise.
    
2.  **SID Translation Mimics 100% Normal Behaviour**  
    Legitimate Windows components constantly call `LookupAccountSid` every time they render file properties, display permissions, or process logs. To an EDR agent, an in-process script translating a few hundred SIDs looks identical to normal operating system behaviour. There are no suspicious process spawns, no noisy command-line flags, and no restricted administrative APIs called.
    

* * *
