Tracking user logon activity

Mark Russinovich has presented a screenshot of the autoruns utility during his Malware Hunting with the Sysinternals Tools session at Teched 2012.
He also reported a slowdown issue while he was at Teched 2012 in Europe in the following blog post.

We can actually see more about these scheduled tasks as he posted the following image:
MS tasks Russinovich

These special scheduled tasks remind me the question that Jonathan Walz (‏@jonwalz)
asked on twitter:

Does anyone have a good method for detecting a logon or unlock of a computer (besides the security log (way too chatty)) with WMI?

Well, you may wonder what’s the link between the scheduled tasks from Microsoft on Mark’s laptop and Jonathan’s question ?

I’ve actually been using these kind of scheduled tasks to track user logon activity as the scheduler has now new triggers: Logon,SessionUnlock,RemoteDisconnect,ConsoleConnect,RemoteConnect,SessionLock,RemoteConnect and ConsoleDisconnect

I have been using the following code in quick and dirty mode to create all these local tasks:


Function Get-Template
{
param($trigger)
    $template = @"
    <?xml version="1.0" encoding="UTF-16"?>
    <Task version="1.3" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
      <RegistrationInfo>
        <Date>2011-01-27T17:29:29.0199265</Date>
        <Author>SYSTEM</Author>
      </RegistrationInfo>
    $trigger
      <Principals>
        <Principal id="Author">
          <UserId>S-1-5-18</UserId>
          <RunLevel>HighestAvailable</RunLevel>
        </Principal>
      </Principals>
      <Settings>
        <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
        <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
        <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
        <AllowHardTerminate>true</AllowHardTerminate>
        <StartWhenAvailable>false</StartWhenAvailable>
        <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
        <IdleSettings>
          <StopOnIdleEnd>true</StopOnIdleEnd>
          <RestartOnIdle>false</RestartOnIdle>
        </IdleSettings>
        <AllowStartOnDemand>true</AllowStartOnDemand>
        <Enabled>true</Enabled>
        <Hidden>false</Hidden>
        <RunOnlyIfIdle>false</RunOnlyIfIdle>
        <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
        <UseUnifiedSchedulingEngine>false</UseUnifiedSchedulingEngine>
        <WakeToRun>false</WakeToRun>
        <ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
        <Priority>7</Priority>
      </Settings>
      <Actions Context="Author">
        <Exec>
          <Command>$env:systemroot\System32\WindowsPowerShell\v1.0\powershell.exe</Command>
          <Arguments>-ExecutionPolicy RemoteSigned -File "$env:systemroot\scripts\Get-userinfo.ps1"</Arguments>
        </Exec>
      </Actions>
    </Task>
"@
    return $template
} # end of function

Function Get-SessionTrigger
{
param($trigger)
    $sessiontrigger = @"
      <Triggers>
        <SessionStateChangeTrigger>
          <Enabled>true</Enabled>
            <StateChange>$trigger</StateChange>
        </SessionStateChangeTrigger>
      </Triggers>
"@
    return $sessiontrigger
}

# Handle the logon trigger
$logontrigger = @"
  <Triggers>
    <LogonTrigger>
      <Enabled>true</Enabled>
    </LogonTrigger>
  </Triggers>
"@

# Create the Logon task
$xml = Get-Template -trigger $logontrigger
$xml | Out-File -FilePath ($env:temp +"\tmp.xml") -Encoding Unicode -Force 
Invoke-Expression -Command ("schtasks.exe /create /RU SYSTEM /TN Logon /F /XML " + ($env:temp +"\tmp.xml"))


# Define an array of each connection state
$arraytriggersstate = @(
      "SessionUnlock",
      "RemoteDisconnect",
      "ConsoleConnect",
      "RemoteConnect",
      "SessionLock",
      "RemoteConnect",
      "ConsoleDisconnect"
)

# Loop into the array and create the task
for ($i = 0 ; $i -lt $arraytriggersstate.count ; $i++)
{
    Write-Host -ForegroundColor Green -Object ($arraytriggersstate[$i])
    $xml = Get-Template -trigger  (Get-SessionTrigger -trigger $arraytriggersstate[$i])
    $xml | Out-File -FilePath ($env:temp +"\tmp.xml") -Encoding Unicode -Force 
    Invoke-Expression -Command ("schtasks.exe /create /RU SYSTEM /F /TN " + $arraytriggersstate[$i] + " /XML " + ($env:temp +"\tmp.xml"))
}

The tasks names are important as I’ve been extracting the last tasks names from the new Microsoft-Windows-TaskScheduler/Operational log to know what the user did and writing it to a CSV file that can be read afterward by custom helpdesk tools.

Here is the XML query passed to the Get-WinEvent cmdlet I’ve been using in my Get-userinfo.ps1 script:

  # Wait a little bit until event 129 occurs
 Start-Sleep -Seconds 10
 
 $query =@"
<QueryList>
 <Query Id="0" Path="Microsoft-Windows-TaskScheduler/Operational">
    <Select Path="Microsoft-Windows-TaskScheduler/Operational">*[System[Provider[@Name='Microsoft-Windows-TaskScheduler'] and (Level=4 or Level=0) and ( Task = 129 ) and TimeCreated[timediff(@SystemTime) &lt;=200000 ]]]</Select>
 </Query>
</QueryList>
"@

To know who logged on, I’m using the technique I’ve previously described in the following post Get Logged on users.

As far as I remember, there’s another way to play with logon triggers. It was published as a powershell tip in April on powershell.com and using the Register-ObjectEvent cmdlet and the [Microsoft.Win32.SystemEvents] .net objects.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s