A Deep Dive Into Windows Scheduled Tasks and The Processes Running Them

Nasreddine Bencherchali
9 min readNov 1, 2020

--

Task Scheduler

In my last blog post I talked about windows system processes in general, their child-parent relationship and gave a brief description of each (See link below).

Today I want to refocus on specific processes and talk about schedule tasks and the schedule task service.

Malware authors have often used schedule tasks as persistence mechanisms as they are a reliable way to make their malicious code run in a recurring way.

From a threat hunting perspective it is necessary to grasp how schedule tasks are run and understand the commands and command line arguments associated with their process(es).

Today, we’ll take a look at how schedule tasks get created with the “schtasks.exe” and “at.exe” commands and the services / processes (svchost.exe, taskhostw.exe, taskeng.exe) responsible for running them.

Tasks and The Task Scheduler Service

MSDN is filled with details about the task scheduler, its API and how it works. So I will not reinvent the wheel with this one. I’ll only quote what’s necessary to get us started in our discussion. Starting by the definition of what is the task scheduler service.

The Task Scheduler service allows you to perform automated tasks on a chosen computer. With this service, you can schedule any program to run at a convenient time for you or when a specific event occurs. The Task Scheduler monitors the time or event criteria that you choose and then executes the task when those criteria are met. — MSDN

The task scheduler runs tasks, which defines the work that the task scheduler will perform. They consists of the following components.

https://docs.microsoft.com/en-us/windows/win32/taskschd/images/taskcomponents.png
  • Triggers: The conditions to start a task.
  • Actions: The actions that’ll get executed when the task is run.
  • Principals: The security context in which the task is run.
  • Settings: The different settings to run a task. For example: “AllowStartOnDemand” will let us run this task outside of its defined run time.
  • Registration Information: Contains information about when the task was created, who created the task…etc.
  • Data: Additional information that can be used when executing a task. (We’ll talk more about this later).

All of this information and more can be found at MSDN via the link below.

Now we understand a little bit of what makes a task, let’s see how we can create one via command line.

Creating Tasks Via Command Line

“AT.EXE”

Just for reference, let’s begin by taking a look at the deprecated command “at.exe” and see how to create a task.

The command above will create a task that’ll run every “Sunday”, “Monday” and “Tuesday” at 11:11 and will executed the file named “MALWARE.EXE”. It’s as simple as that.

You can use other flags like specifying a remote computer name or the “/yes” flag for answering yes to all queries and many more. Take a look at MSDN for the full list.

To give you an idea, here is a small description of what to look for when hunting for the “at.exe” command. (This is by no mean exhaustive)

Path: %SystemRoot%\System32\at.exePrivilege: To use at, you must be a member of the local Administrators group.What to look for while Hunting: Check the command line being passed when creating a task and see if the executable or the command as a whole are benign.Artifacts:- Creation of At[x].job files in the “%SystemRoot%\Tasks” folder where [x] is the ID of the job.- Creation of XML files in the %SystemRoot%\System32\Tasks folder.- If enabled, then Task creation and modification in “Microsoft-Windows-TaskScheduler/Operational” event log.

“SCHTASKS.EXE”

Since “At.exe” got deprecated in Windows 8, the modern way to create schedule tasks on modern windows system is to use the “schtasks.exe” command line utility.

Similar to the “At.exe” command (But actually more powerful), the “schtasks.exe” offers a lot of flags to customize the tasks to our needs.

From a threat hunting perspective one of the key things we’re interested in knowing is “what the task is going to execute”. The flag responsible for that is the “TR” (Task Run) flag.

So if we take an example of a malicious task creation, we’ll see something similar to command below.

any.run Report

Where the “/TN” flag refers to the task name, in this case it is “Kg1N7U38” and the “TR” refers to the command that’ll get executed.

Other flags such as the “/Run” flag for running an already existing task or the “/ST” and “/ED” for the “Start Date” and “End Date” respectively are worth taking a look at and monitoring.

As always for a complete list of the available commands, please refer to MSDN.

One again here is a small description of what to hunt for with the “schtasks.exe” command.

Path: %SystemRoot%\System32\schtasks.exePrivilege: Any user can create a task. To run a task as privileged account obviously you need an administrator account / password.What to look for while Hunting:- Check the parent process calling the utility to determine if its allowed to create tasks or not.- Check the command line being passed to the “/TR” when creating a task and see if the executable or the command as a whole are benign.- Look for any unusual task name via the flag “/TN”.Artifacts:- Creation of XML files in the %SystemRoot%\System32\Tasks folder.- If enabled, then Task creation and modification in “Microsoft-Windows-TaskScheduler/Operational” event log.

Once a task gets created, a descriptive XML file that contains all the information regarding the task will be generated in the following directory “%SystemRoot%\System32\Tasks”.

Please note that tasks created via the “taskschd.msc” interface will get handled by the “svchost.exe” process hosting the “Task Scheduler” Service.

Also task creation via scripting or API is not covered in this blog post.

Running Tasks (svchost.exe / taskeng.exe / taskhostw.exe)

Now that we covered how tasks can be created, it’s time to take a look at the process or processes that’ll be running these tasks.

The service responsible for running schedule tasks is called the “Task Scheduler” Service. It starts with the operating system and its part of the “netsvcs” group in the “svchost” registry key.

You can catch it running in the process tree by looking at the “svchost.exe” process with the following command line: “svchost.exe -k netsvcs -p -s Schedule” on Windows 10 Version 1703 and above (On computers with 3.5GB ram or more) and without the “-s Schedule” flag On windows versions before 1703.

“TASKENG.EXE”

On older windows versions any task that runs will spawn a “taskeng.exe” (short for Task Engine) process and the “taskeng.exe” process will spawn the executable(s) requested by the task. So in a process tree it’ll look something like this.

The “taskeng.exe” process will have the following syntax:

Everything is self-explanatory in this syntax except maybe for the “options” part which will be chosen depending on the configuration of the task. For example:

If the user chose to run the task at the highest privileges and in an interactive way the options part will get replaced by the following.

“Interactive:Highest[1]”

So in older version of windows you can look in the logs for any parent-child relationship between “taskeng.exe” and “svchost –k netsvcs”, and between “taskeng.exe” and a process to search for malicious processes launched via tasks.

“SVCHOST.EXE –K NETSVCS –P –S SCHEDULE”

Since Windows 10 Version 1511, tasks were no longer run from “taskeng.exe”. In fact, “taskeng.exe” no longer exists on the system in newer versions of windows.

Nowadays, tasks are run directly by the “svchost.exe” process responsible for the “Task Scheduler” Service.

So when a task is run, you’ll see the executable as a child of the “svchost.exe -k netsvcs -p -s Schedule” process (See figure below).

So in the example above we can see “calc.exe” as a child of “svchost.exe” which means that there is a task on the system configured to run “calc.exe” at a certain time.

We can use this information to hunt for processes executed via a task by looking at the relationship of processes where the svchost.exe -k netsvcs -p -s Schedule” is a parent.

Note: The “svchost.exe” must contain at least the “-k netsvcs” flag. If a different flag or no flag is present it cannot be considered as a task and should be treated differently.

“TASKHOSTW.EXE” And Its Arguments

One thing I hope you noticed in the previous figure is the “taskhostw.exe” process.

The “taskhostw.exe” process is a special process, belonging to a larger family of hosting processes in windows.

Similar to “dllhost.exe” or “svchost.exe”, the “taskhostw.exe” process is designed to host DLL’s that are run from TASKS.

If we searched the “%SystemRoot%\System32\Tasks” folder, we can find some tasks that have as an action not an executable but a COM Object reference (I.e: CLSID) to a DLL.

Below is an example of a “.NET Framework” task that is designed to run the “ngentasklauncher.dll” (NGenTaskLauncher).

Once this task gets executed a “taskhostw.exe” will spawn as a child of the “svchost.exe” process.

You’ll notice that “taskhostw.exe” was launched with the argument “/RuntimeWide” the same argument that was mentioned in the “<Data>” section in the Task XML definition above.

In fact, similar to tasks that run executables. “taskhostw.exe” can use arguments as well. And one can go a step further and provide a dynamic argument.

  • “$(Arg0)” Flag

I’m pretty sure that you’ve run into the following command before (Especially in logs).

To help us understand this, let’s take a look at MSDN.

Some action properties that are of type BSTR can contain $(Arg0), $(Arg1), …, $(Arg32) variables in their string values. These variables are replaced with the values that are specified in the params parameter of the IRegisteredTask::Run and IRegisteredTask::RunEx methods or are contained within the event trigger for the task. — MSDN

And if we take a look at some windows default tasks we can find this notation in a lot of them. (See example below)

  • “{222A245B-E637–4AE9-A93F-A59CA119A75E}” Argument

One other common argument you’ll see “taskhostw.exe” running is this “{222A245B-E637–4AE9-A93F-A59CA119A75E}”. If you see his one in your logs, then it is referring to two tasks running inside “taskhostw.exe”

  • %SystemRoot%System32\Tasks\Microsoft\Windows\Wininet\CacheTask
  • %SystemRoot%System32\Tasks\Microsoft\Windows\Multimedia\SystemSoundsService

I couldn’t find the source of the referenced {CLSDI} but it persisted across multiple reboots and machines.

Note: On Windows 7 the process name was “taskhost.exe” instead of “taskhostw.exe” and in windows 8 an additional process was added and removed in future versions of windows named “taskhostex.exe”.

Conclusion

In this blog post we’ve taken a look at:

  • How tasks are structured and the services responsible for running them.
  • Command line utility used to create tasks.
  • The parent child relationship between task scheduler service and the tasks.
  • Command line arguments of certain executables such as “taskeng.exe” and “taskhostw.exe”.

I hope you enjoyed this post and learned something along the way. If you have any feedback or suggestions, please send them my way on twitter @nas_bench.

Happy Hunting.

Resources

--

--