Powershell
What is Powershell?
Powershell is the Windows Scripting Language and shell environment that is built using the .NET framework.
This also allows Powershell to execute .NET functions directly from its shell. Most Powershell commands, called cmdlets, are written in .NET. Unlike other scripting languages and shell environments, the output of these cmdlets are objects - making Powershell somewhat object oriented. This also means that running cmdlets allows you to perform actions on the output object(which makes it convenient to pass output from one cmdlet to another). The normal format of a cmdlet is represented using Verb-Noun; for example the cmdlet to list commands is called Get-Command
.
Common verbs to use include:
- Get
- Start
- Stop
- Read
- Write
- New
- Out
To get the full list of approved verbs, visit this link.
Basic Powershell Commands
Now that we've understood how cmdlets works - let's explore how to use them! The main thing to remember here is that Get-Command and Get-Help are your best friends!
Using Get-Help
Get-Help
displays information about a cmdlet. To get help about a particular command, run the following:
Get-Help Command-Name
You can also understand how exactly to use the command by passing in the -examples
flag. This would return output like the following:
Using Get-Command
Get-Command
gets all the cmdlets installed on the current Computer. The great thing about this cmdlet is that it allows for pattern matching like the following
Get-Command Verb-* or Get-Command *-Noun
Running Get-Command New-*
to view all the cmdlets for the verb new displays the following:
Object Manipulation
In the previous task, we saw how the output of every cmdlet is an object. If we want to actually manipulate the output, we need to figure out a few things:
- passing output to other cmdlets
- using specific object cmdlets to extract information
The Pipeline(|) is used to pass output from one cmdlet to another. A major difference compared to other shells is that instead of passing text or string to the command after the pipe, powershell passes an object to the next cmdlet. Like every object in object oriented frameworks, an object will contain methods and properties. You can think of methods as functions that can be applied to output from the cmdlet and you can think of properties as variables in the output from a cmdlet. To view these details, pass the output of a cmdlet to the Get-Member cmdlet
Verb-Noun | Get-Member
An example of running this to view the members for Get-Command is:
Get-Command | Get-Member -MemberType Method
From the above flag in the command, you can see that you can also select between methods and properties.
Creating Objects From Previous cmdlets
One way of manipulating objects is pulling out the properties from the output of a cmdlet and creating a new object. This is done using the Select-Object
cmdlet.
Here's an example of listing the directories and just selecting the mode and the name:
You can also use the following flags to select particular information: - first - gets the first x object - last - gets the last x object - unique - shows the unique objects - skip - skips x objects
Filtering Objects
When retrieving output objects, you may want to select objects that match a very specific value. You can do this using the Where-Object
to filter based on the value of properties.
The general format of the using this cmdlet is
Verb-Noun | Where-Object -Property PropertyName -operator Value
Verb-Noun | Where-Object {$_.PropertyName -operator Value}
The second version uses the $_ operator
to iterate through every object passed to the Where-Object
cmdlet.
Powershell is quite sensitive so make sure you don't put quotes around the command!
Where -operator is a list of the following operators:
-Contains
: if any item in the property value is an exact match for the specified value-EQ
: if the property value is the same as the specified value-GT
: if the property value is greater than the specified value
For a full list of operators, use this link.
Here's an example of checking the stopped processes:
Sort Object
When a cmdlet outputs a lot of information, you may need to sort it to extract the information more efficiently. You do this by pipe lining the output of a cmdlet to the Sort-Object cmdlet.
The format of the command would be
Verb-Noun | Sort-Object
Here's an example of sort the list of directories:
Example
What is the location of the file interesting-file.txt
?
Get-ChildItem -Path C:\ -Include *interesting-file.txt* -File -Recurse -ErrorAction SilentlyContinue
Specify the contents of this file
PS C:\Users\Administrator> Get-Content 'C:\Program Files\interesting-file.txt.txt'
notsointerestingcontent
How many cmdlets are installed on the system(only cmdlets, not functions and aliases)?
PS C:\Users\Administrator> Get-Command | Where-Object -Property CommandType -eq Cmdlet | measure
Count : 6638
Average :
Sum :
Maximum :
Minimum :
Property :
Get the MD5 hash of interesting-file.txt
PS C:\Users\Administrator> Get-FileHash 'C:\Program Files\interesting-file.txt.txt' -Algorithm MD5
Algorithm Hash Path
--------- ---- ----
MD5 49A586A2A9456226F8A1B4CEC6FAB329 C:\Program Files\interesting-...
What is the command to get the current working directory?
PS C:\Users\Administrator> Get-Location
Path
----
C:\Users\Administrator
What command would you use to make a request to a web server?
Invoke-WebRequest
Base64 decode the file b64.txt on Windows.
PS C:\Users\Administrator\Desktop> $data = Get-Content .\b64.txt
PS C:\Users\Administrator\Desktop> [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($data))
this is the flag - ihopeyoudidthisonwindows
Enumeration
The first step when you have gained initial access to any machine would be to enumerate. We'll be enumerating the following: - users - basic networking information - file permissions - registry permissions - scheduled and running tasks - insecure files
Examples
How many users are there on the machine?
PS C:\Users\Administrator\Desktop> Get-LocalUser | measure
Count : 5
Average :
Sum :
Maximum :
Minimum :
Property :
Which local user does this SID(S-1-5-21-1394777289-3961777894-1791813945-501) belong to?
PS C:\Users\Administrator\Desktop> Get-LocalUser | Select sid,name
SID Name
--- ----
S-1-5-21-1394777289-3961777894-1791813945-500 Administrator
S-1-5-21-1394777289-3961777894-1791813945-503 DefaultAccount
S-1-5-21-1394777289-3961777894-1791813945-1008 duck
S-1-5-21-1394777289-3961777894-1791813945-1009 duck2
S-1-5-21-1394777289-3961777894-1791813945-501 Guest
How many users have their password required values set to False?
PS C:\Users\Administrator\Desktop> Get-LocalUser | Select passwordrequired
PasswordRequired
----------------
True
False
False
False
False
How many local groups exist?
PS C:\Users\Administrator\Desktop> Get-LocalGroup | measure
Count : 24
Average :
Sum :
Maximum :
Minimum :
Property :
What command did you use to get the IP address info?
PS C:\Users\Administrator\Desktop> Get-NetIPAddress
IPAddress : fe80::3098:302d:f5f5:a941%7
InterfaceIndex : 7
InterfaceAlias : Local Area Connection* 3
AddressFamily : IPv6
Type : Unicast
PrefixLength : 64
PrefixOrigin : WellKnown
SuffixOrigin : Link
AddressState : Preferred
ValidLifetime : Infinite ([TimeSpan]::MaxValue)
PreferredLifetime : Infinite ([TimeSpan]::MaxValue)
SkipAsSource : False
PolicyStore : ActiveStore
How many ports are listed as listening?
PS C:\Users\Administrator\Desktop> Get-NetTcpConnection | Where-Object -Property State -eq Listen | measure
Count : 20
Average :
Sum :
Maximum :
Minimum :
Property :
What is the remote address of the local port listening on port 445?
PS C:\Users\Administrator\Desktop> Get-NetTcpConnection | Where-Object -Property LocalPort -eq 445
LocalAddress LocalPort RemoteAddress RemotePort State AppliedSetting
------------ --------- ------------- ---------- ----- --------------
:: 445 :: 0 Listen
How many patches have been applied?
PS C:\Users\Administrator\Desktop> Get-HotFix | measure
Count : 20
Average :
Sum :
Maximum :
Minimum :
Property :
When was the patch with ID KB4023834 installed?
PS C:\Users\Administrator\Desktop> Get-HotFix | -Id KB4023834
Source Description HotFixID InstalledBy InstalledOn
------ ----------- -------- ----------- -----------
EC2AMAZ-5M... Update KB4023834 EC2AMAZ-5M13VM2\A... 6/15/2017 12:00:00 AM
Find the contents of a backup file.
PS C:\Users\Administrator\Desktop> Get-ChildItem -Path C:\ -Include *.bak* -File -Recurse -ErrorAction SilentlyContinue
Directory: C:\Program Files (x86)\Internet Explorer
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/4/2019 12:42 AM 12 passwords.bak.txt
PS C:\Users\Administrator\Desktop> Get-Content "C:\Program Files (x86)\Internet Explorer\passwords.bak.txt"
backpassflag
Search for all files containing API_KEY
PS C:\Users\Administrator\Desktop> Get-ChildItem C:\* -Recurse | Select-String -pattern API_KEY
[...]
C:\Program Files (x86)\AWS SDK for .NET\bin\Net35\AWSSDK.APIGateway.dll:17824: TLS_1_0 GB_6_1 Nullable`1 L
C:\Users\Public\Music\config.xml:1:API_KEY=fakekey123
Select-String : The file C:\Windows\appcompat\Programs\Amcache.hve cannot be read: The process cannot access t
'C:\Windows\appcompat\Programs\Amcache.hve' because it is being used by another process.
At line:1 char:31
+ Get-ChildItem C:\* -Recurse | Select-String -pattern API_KEY
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Select-String], ArgumentException
+ FullyQualifiedErrorId : ProcessingFile,Microsoft.PowerShell.Commands.SelectStringCommand
What command do you do to list all the running processes?
PS C:\Users\Administrator\Desktop> Get-Process
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
118 8 21044 12876 0.33 1764 0 amazon-ssm-agent
198 13 3712 17700 0.16 4968 2 ApplicationFrameHost
190 12 3944 15140 12.39 3768 2 conhost
206 10 1760 3932 0.27 524 0 csrss
118 8 1312 3584 0.08 592 1 csrss
222 13 1820 8300 2.73 2692 2 csrss
91 7 1276 6308 0.02 4268 2 dllhost
316 18 13232 29276 0.09 924 1 dwm
371 30 16356 41340 3.03 2784 2 dwm
1341 59 23512 77452 13.08 2100 2 explorer
What is the path of the scheduled task called new-sched-task?
PS C:\Users\Administrator\Desktop> Get-ScheduledTask -TaskName new-sched-task
TaskPath TaskName State
-------- -------- -----
\ new-sched-task Ready
Who is the owner of the C:\
PS C:\Users\Administrator\Desktop> Get-Acl c:/
Directory:
Path Owner Access
---- ----- ------
C:\ NT SERVICE\TrustedInstaller CREATOR OWNER Allow 268435456...
Basic Scripting Challenge
Now that we have run powershell commands, let's actually try write and run a script to do more complex and powerful actions.
For this ask, we'll be using PowerShell ISE(which is the Powershell Text Editor). To show an example of this script, let's use a particular scenario. Given a list of port numbers, we want to use this list to see if the local port is listening. Open the listening-ports.ps1 script on the Desktop using Powershell ISE. Powershell scripts usually have the .ps1 file extension.
$system_ports = Get-NetTCPConnection -State Listen
$text_port = Get-Content -Path C:\Users\Administrator\Desktop\ports.txt
foreach($port in $text_port){
if($port -in $system_ports.LocalPort){
echo $port
}
}
````
On the first line, we want to get a list of all the ports on the system that are listening. We do this using the Get-NetTCPConnection cmdlet. We are then saving the output of this cmdlet into a variable. The convention to create variables is used as:
```powershell
$variable_name = value
On the next line, we want to read a list of ports from the file. We do this using the Get-Content cmdlet. Again, we store this output in the variables. The simplest next step is iterate through all the ports in the file to see if the ports are listening. To iterate through the ports in the file, we use the following
foreach($new_var in $existing_var){}
````
This particular code block is used to loop through a set of object. Once we have each individual port, we want to check if this port occurs in the listening local ports. Instead of doing another for loop, we just use an if statement with the `-in` operator to check if the port exists the LocalPort property of any object. A full list of if statement comparison operators can be found [here](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators?view=powershell-6). To run script, just call the script path using Powershell or click the green button on Powershell ISE:
![f363825303499dc6d9652b164781c82a.png](img/f363825303499dc6d9652b164781c82a.png)
### Examples
Now that we've seen what a basic script looks like - it's time to write one of your own. The emails folder on the Desktop contains copies of the emails John, Martha and Mary have been sending to each other(and themselves). Answer the following questions with regards to these emails(try not to open the files and use a script to answer the questions).
Scripting may be a bit difficult, but here is a good resource to use:
```powershell
$files = Get-ChildItem C:\Users\Administrator\Desktop\emails -Recurse -File | %{$_.FullName}
foreach($file in $files){
Get-Content $file
}
PS C:\Users\Administrator\Desktop> $files = Get-ChildItem C:\Users\Administrator\Desktop\emails -Recurse -File | %{$_.FullName}
foreach($file in $files){
Get-Content $file
}
to: john
from: john
just a test email to see if this works
to: mary
from: john
Hi Mary,
I was wondering how that update was coming along?
John
to: Martha
from: John
Hi Martha,
I got some errors trying to access my passwords file - is there any way you can help? Here is the output I got
file corrupted, fix thisfile cofile corrupted, fix thisrrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix thisfile corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix thisfile corrupted, fix thisfile corrupted, fix thisfile corrupted, fix thisfile corrupted, fix thisfile corrupted, fix thisfile corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix thisfilfile corrupted, fix thise corrupted, fix thisfile corrupted, fix this
file corrupted, fix this
file corrupted, fix this
file corrupted, fix thisfile corrupted, fix thisfile corrupted, fix this
file corrupted, fix thisfile corrupted, fix thisfile corrupted, fix this
segmentation fault, dumping core
to: John
from: Martha
Hi John,
Wow that's very weird - I'll look into that for you
Martha
from: Martha
to: Mary
Hi Mary,
Let me know if you needed help with your update - it looks like it's going quite slow.
Martha
to: john
from: Martha
Hi John,
I managed to fix the corrupted file to get the output, but the password is buried somewhere in these logs:
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
fixing file - please wait
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
10% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
50% progress
88% progress
88% progress
88% progress
88% progress
88% progress
88% progress
88% progress
88% progress
88% progress
almost done
almost done
almost done
almost done
almost done
almost done
almost done
password is johnisalegend99
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
function complete
to: John
From: Mary
Hi John,
It looks like we have hit a couple of speed bumps - i'll keep you updated on the progress. We expect to finish by 11/11/2020
Mary
to: Mary
From: Mary
Well I don't really know how to do this update: check this link
https://www.howtoworkwell.rand/
What file contains the password?
PS C:\Users\Administrator\Desktop> Get-ChildItem C:\Users\Administrator\Desktop\emails -Recurse -File | Select-String -Pattern "johnisalegend99"
emails\martha\Doc3M.txt:106:password is johnisalegend99
What file contains the password?
PS C:\Users\Administrator\Desktop> Get-ChildItem C:\Users\Administrator\Desktop\emails -Recurse -File | Select-String -Pattern "https://"
emails\mary\Doc2Mary.txt:5:https://www.howtoworkwell.rand/
Intermediate Scripting
Now that you've learnt a little bit about how scripting works - let's try something a bit more interesting. Sometimes we may not have utilities like nmap and python available, and we are forced to write scripts to do very rudimentary tasks. Why don't you try writing a simple port scanner using Powershell. Here's the general approach to use:
- Determine IP ranges to scan(in this case it will be localhost) and you can provide the input in any way you want
- Determine the port ranges to scan
- Determine the type of scan to run(in this case it will be a simple TCP Connect Scan)
We found a powershell
module here
PS C:\Users\Administrator\Desktop> 130..140 | foreach { port-scan-tcp 127.0.0.1 $_ }
127.0.0.1,tcp,130,Closed
127.0.0.1,tcp,131,Closed
127.0.0.1,tcp,132,Closed
127.0.0.1,tcp,133,Closed
127.0.0.1,tcp,134,Closed
127.0.0.1,tcp,135,Open
127.0.0.1,tcp,136,Closed
Exception calling "ConnectAsync" with "2" argument(s): "An attempt was made to access a socket in a way forbidden by its access
permissions 127.0.0.1:137"
At C:\Users\Administrator\Desktop\port-scan-tcp.ps1:18 char:5
+ $c = $t.ConnectAsync($h,$p)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SocketException
127.0.0.1,tcp,137,Filtered
127.0.0.1,tcp,138,Closed
127.0.0.1,tcp,139,Closed
127.0.0.1,tcp,140,Closed