PowerShell has grown since its introduction in 2003 and implementation in Windows XP in 2006. What started as a closed source, proprietary upgrade to the Command Prompt has now grown into an open-source, resource rich Command Line Interface (CLI) and scripting utility. PowerShell can now be used cross-platform to manage any environment whether that be on-premises or cloud based.
Because of this flexibility PowerShell is used in many aspects of IT, and Security. In this post we will cover some of the basics of using and understanding PowerShell, as well as confirming that what you are seeing is accurate.
PowerShell has an ISE (Integrated Scripting Environment) version that can be used to create PS1 files. These can then be tested and run. You do not need to use the ISE to create PS1 files, any text editor or external ISE will do the trick! (cough Notepad++ cough). The main difference here is being able to test your script immediately.
This is useful for an investigator to know if the malicious PowerShell script was run from
PowerShell.exe. If the ISE executable was used this shows that the person running the script had GUI access. This does not imply that there was a human at that host at the time, tools like AnyDesk, TeamViewer, VNC and even RDP could have been used.
If it was just
powershell.exe then this could have been run from a remotely connected attacker, from a compromised external USB device or even a persistence mechanism such as a registry run key.
PowerShell has the option to hit the Tab key to complete a command. This can be useful if (like me) you regularly forget what the command is called, or which argument to pass to it.
Test this out by typing
'get-‘ then tab through SOOOO many options. You can also use shift-tab to go back through the list. Hours of fun!
The Get-Help command, which can also be called via ‘help’ or ‘man’, is followed by the command that you wish to have explained. This is useful to see what the correct syntax of a command is as well as accepted arguments.
It is not used to distract guards by throwing your adopted-brother at them.
As the name suggests, the Alias command shows alternate commands that will call the same code behind the scenes. From a security perspective it is worth remembering that this can be changed.
While this is rare outside of CTF environments, it is worth knowing how to confirm the commands you are running, and if the output of a command is ever in question, this can be one of your first port-of-calls.
Which gives the following output.
The ‘Name’ field is a little mis-leading as this is technically the ‘Name -> Definition’ field. If you want to show the Aliases for ‘Get-Process’ for example, you would need to run the following command:
Get-Alias -definition Get-Process
Which by default would show the following:
Meaning PS or GPS would give the same result as ‘Get-Process’ and all arguments or piped outputs would also be the same.
Just for fun, I changed ‘PS’ to open Notepad, to show how these can be changed. If you don’t think that is fun, then you are most likely a well-balanced human being. Well done. Get off my blog.
Set-Alias -Name PS -Value C:\Windows\notepad.exe -Option Allscope
The ‘-option Allscope’ at the end is due to this being a protected Alias and gives an error otherwise.
Now when you type PS, you get Notepad.exe launch, which is almost as evil as Calc.exe being launched
This could be used to call a fake process list, in an attempt to confuse the investigator, or more creative aliases could be used to alert an attacker that they are being investigated, or even destroy evidence.
Base64 Encoded Evilness
There is a misconception with less experienced security professionals that any Base64 encoded PowerShell command is evil.
This is simply not true.
I have seen administrators use this technique for logon scripts, companies use this for updating software and of course bad guys.
Base64 in PowerShell needs to be UTF16 encoded. So if you are looking to run a script, ensure you do this first. My example at the start of this post was as follows:
powershell.exe -e QwBsAGUAYQByAAoACgAkAGgAYQB0AHMAbwBmAGYAcwBlAGMAdQByAGkAdAB5ACAAPQAgAHcAcgBpAHQAZQAtAGgAbwBzAHQAIAAnAFAAbABlAGEAcwBlACAAcgBlAGEAZAAgAG0AeQAgAGIAbABvAGcALAAgAGkAdAAgAHcAaQBsAGwAIABtAGEAawBlACAAbQBlACAAZQB2AGUAcgAgAHMAbwAgAGgAYQBwAHAAeQAhACcAIAAKAAoAJABoAGEAdABzAG8AZgBmAHMAZQBjAHUAcgBpAHQAeQA=
Al this is doing is clearing the screen, setting a variable, then calling that variable back:
.$.h.a.t.s.o.f.f.s.e.c.u.r.i.t.y. .=. .w.r.i.t.e.-.h.o.s.t. .'.P.l.e.a.s.e. .r.e.a.d. .m.y. .b.l.o.g.,. .i.t. .w.i.l.l. .m.a.k.e. .m.e. .e.v.e.r. .s.o. .h.a.p.p.y.!.'. .
If you use CyberChef you can use the following simple recipe to go from Base64 to clear text
Key things to look for once you have decoded the text is weird capitalisation, or commands being broken apart with a
+ symbol. These are basic string based detection avoidance techniques.
PowerShell allows the output of a command to be piped into another command. While this sounds similar to Linux, PowerShell outputs are seen as Objects, rather than text.
What this means is that you can manipulate the output with another command rather than trying to move the text around. A good example would be
Get-ChildItem (gci, ls or dir as aliases). This will output the contents of your current directory in its default state.
Below we have a screenshot of PowerShell on a Windows host, vs the obligatory Kali VM I have because… reasons (CTFs mostly).
Both outputs look fairly similar.
If you want to change the output to be by last write time, with Linux I need to change the initial command, using
-t sorts by last modified time. If you pipe the command into something like
sort it sorts by the first character on each line.
For PowerShell you pipe the command into another command such as
Sort-Object LastWriteTime which gives the following
The ability to manipulate the data as an object has some great benefits, such as being able to add or remove fields with
select. However it can also cause the command to be come quite cumbersome and for people who have been scripting in Bash for a long time it can be quite jarring.
Unless you are fortunate enough to have an Endpoint tool that can record commands being run, you will need to manually enable PowerShell logging. The steps to enable this are a blog post of their own. So rather than side-track this post I will leave a couple of links here to external sites. (this is not an endorsement of products)
(yes is actually has a
t on the end of the Mandiant URL… typos, amirite?)
Logging is essential if you want to see what PowerShell was doing on the host, especially if the script file was deleted before the investigation started!
This was a whistle-top tour of PowerShell and I am planning to follow up with shorter, more focussed posts. Judging by my posting schedule the next one should be out just before the heat death of the universe! I am also planning on dropping these on a YouTube video on my channel, but the process is a little more involved and requires a thing called “planning”, which I am unfamiliar with.
Now for the PowerShell conclusion! PowerShell is a really powerful tool that allows for manipulation of data in many ways. This is why threat actors like it so much! There is a lot more I could cover around how malicious scripts can be run or blocked, but that is better covered by someone on the pentesting side of security.
Learning PowerShell as a defender isn’t about learning how an attacker will use it, although that will be a useful side effect, it is about learning how to quickly and efficiently collect data from a compromised host. Once you have mastered this, you can use PowerShell to scale that up to as many hosts as you need to access.
Running scripts across an entire domain may feel daunting, but this is a great way to check for compromise at scale with no expensive or fancy tools.
Now go subscribe to my YouTube channel! and I will work on my videos