What is Powershell?

PowerShell là ngôn ngữ scripting của Windows và là một shell environment được xây dựng bằng .NET framework. Điều này đồng nghĩa với việc chúng ta có thể thực thi các hàm của .NET trong PowerShell.

Đa số các câu lệnh PowerShell (còn được gọi là các cmdlet) đều được viết bằng .NET nên output của nó là các đối tượng nên có thể nói rằng PowerShell mang tính hướng đối tượng. Dạng đơn giản nhất của cmdlet là động từ-danh từ, ví dụ: câu lệnh để liệt kê danh sách các câu lệnh là Get-Command.

Một số động từ thường gặp:

  • Get
  • Start
  • Stop 
  • Read
  • Write
  • New
  • Out

Seealso

Approved Verbs for PowerShell Commands - PowerShell | Microsoft Learn

Basic Powershell Commands

Using Get-Help

Câu lệnh Get-Help giúp hiển thị thông tin hướng dẫn về một câu lệnh nào đó. Ví dụ:

Get-Help Command-Name

Có thể thêm flag -Examples để in ra ví dụ:

Get-Help Get-Command -Examples
 
NAME
    Get-Command
 
SYNOPSIS
    Gets all commands.
 
    -------- Example 1: Get cmdlets, functions, and aliases --------
    Get-Command
    -------- Example 2: Get commands in the current session --------
    Get-Command -ListImported
    ------- Example 3: Get cmdlets and display them in order -------
    Get-Command -Type Cmdlet | Sort-Object -Property Noun | Format-Table -GroupBy Noun
    ------------- Example 4: Get commands in a module -------------
    Get-Command -Module Microsoft.PowerShell.Security, Microsoft.PowerShell.Utility
    ---------- Example 5: Get information about a cmdlet ----------
    Get-Command Get-AppLockerPolicy

Using Get-Command

Câu lệnh Get-Command liệt kê tất cả các cmdlet trên máy hiện tại. Câu lệnh này cho phép sử dụng pattern matching. Ví dụ: Get-Command Verb-* hoặc Get-Command *-Noun.

Câu lệnh sau sẽ giúp liệt kê tất cả các cmdlet có động từ là New:

Get-Command New-*

Object Manipulation

Chúng ta có thể dùng toán tử | (pipeline) để truyền output từ cmdlet này sang cmdlet khác (tương tự như Linux). Điểm khác biệt lớn nhất giữa PowerShell và các loại shell khác là nó truyền object sang cmdlet kế tiếp thay vì truyền chuỗi.

Các object cũng có các thuộc tính và phương thức tương tự như một object trong OOP. Có thể xem các thuộc tính là các biến có trong output của cmdlet và các phương thức là các hàm mà có thể áp dụng trên output của cmdlet. Để xem thuộc tính hoặc phương thức của một output, chúng ta có thể truyền nó vào cmdlet Get-Member như sau:

Verb-Noun | Get-Member

Ví dụ:

Get-Command | Get-Member -MemberType Method
 
   TypeName: System.Management.Automation.AliasInfo
 
Name             MemberType Definition
----             ---------- ----------
Equals           Method     bool Equals(System.Object obj)
GetHashCode      Method     int GetHashCode()
GetType          Method     type GetType()
ResolveParameter Method     System.Management.Automation.ParameterMetadata ResolveParameter(string name)
ToString         Method     string ToString()
 
   TypeName: System.Management.Automation.FunctionInfo
 
Name             MemberType Definition
----             ---------- ----------
Equals           Method     bool Equals(System.Object obj)
GetHashCode      Method     int GetHashCode()
GetType          Method     type GetType()
ResolveParameter Method     System.Management.Automation.ParameterMetadata ResolveParameter(string name)
ToString         Method     string ToString()
 
   TypeName: System.Management.Automation.CmdletInfo
 
Name             MemberType Definition
----             ---------- ----------
Equals           Method     bool Equals(System.Object obj)
GetHashCode      Method     int GetHashCode()
GetType          Method     type GetType()
ResolveParameter Method     System.Management.Automation.ParameterMetadata ResolveParameter(string name)
ToString         Method     string ToString()

Để xem các thuộc tính thì có thể dùng option -MemberType Property.

Creating Objects From Previous Cmdlets

Chúng ta có thể trích xuất các thuộc tính từ output của một cmdlet để tạo thành một object mới thông qua cmdlet Select-Object.

Ví dụ bên dưới liệt kê các thư mục mà chỉ trích xuất mode và name:

Get-ChildItem | Select-Object -Property Mode, Name
 
Mode  Name
----  ----
d-r-- Documents
d-r-- Downloads
d-r-- Music
d-r-- Pictures
d---- temp
d-r-- Videos

Chúng ta cũng có thể dùng các option sau đối với output là mảng các object:

  • -First n - lấy n object đầu tiên.
  • -Last n - lấy n object cuối cùng.
  • -Unique - chỉ hiển thị các object độc nhất.
  • -Skip n - bỏ qua n object.

Filtering Objects

Để lọc ra các object thỏa một điều kiện nào đó thì ta có thể dùng cmdlet Where-Object.

Dạng tổng quát:

Verb-Noun | Where-Object -Property PropertyName -Operator Value
Verb-Noun | Where-Object {$_.PropertyName -Operator Value}

Câu lệnh thứ 2 sử dụng toán tử $_ để lặp qua từng object có trong mảng các object.

Một số giá trị của -Operator:

  • -Contains: chứa một giá trị nào đó.
  • -EQ: so sánh bằng.
  • -GT: so sánh lớn hơn.

Seealso

about Comparison Operators - PowerShell | Microsoft Learn

Ví dụ bên dưới tìm ra các dic đã bị dừng:

Get-Service | Where-Object -Property Status -eq Stopped

Sort-Object

Để sắp xếp các object thì có thể pipe với cmdlet Sort-Object.

Ví dụ bên dưới sẽ sắp xếp các thư mục con:

Get-ChildItem | Sort-Object

Exercises

What is the location of the file "interesting-file.txt"

PS C:\Users\Administrator> Get-ChildItem -Path C:\ -File -Recurse -Filter *interesting-file.txt*

Tìm được ở thư mục C:\Program Files

Specify the contents of this file

PS C:\Users\Administrator> Get-Content -Path "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 -CommandType Cmdlet | Measure-Object -Line

Kết quả là 6638.

Get the MD5 hash of interesting-file.txt

PS C:\Users\Administrator> Get-FileHash -Path "C:\Program Files\interesting-file.txt.txt" -Algorithm MD5

Kết quả là 49A586A2A9456226F8A1B4CEC6FAB329

What is the command to get the current working directory?

Get-Location

Does the path "C:\Users\Administrator\Documents\Passwords" Exist (Y/N)?

PS C:\Users\Administrator> Test-Path -Path "C:\Users\Administrator\Documents\Passwords"
False

What command would you use to make a request to a web server?

Invoke-WebRequest

Ví dụ:

$response = Invoke-WebRequest -Uri "http://www.example.com"
$response.Content

Base64 decode the file b64.txt on Windows.

Tìm vị trí của file:

Get-ChildItem -Path C:\ -Recurse -Filter *b64.txt*

Tìm được ở thư mục C:\Uses\Administrator\Desktop.

Sử dụng ba câu lệnh sau:

# Read the content of the file
$base64Content = Get-Content -Path "C:\Uses\Administrator\Desktop\b64.txt" -Raw
 
# Decode the Base64 content
$decodedContent = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64Content))
 
# Output the decoded content
Write-Output $decodedContent

Optionn -Raw dùng để lấy nội dung của file dưới dạng một chuỗi.

Flag:

ihopeyoudidthisonwindows

Enumeration

Khi thâm nhập được vào máy mục tiêu, chúng ta cần enumerate những thông tin sau:

  • Các người dùng
  • Thông tin mạng cơ bản
  • Các quyền trên tập tin
  • Các quyền trên registry
  • Các task đang chạy và các task được lập lịch
  • Các tập tin không an toàn

How many users are there on the machine?

PS C:\Users\Administrator> Get-LocalUser

Thu được 5 người dùng: Administrator, DefaultAccount, duck, duck2, Guest.

Which local user does this SID(S-1-5-21-1394777289-3961777894-1791813945-501) belong to?

PS C:\Users\Administrator> Get-LocalUser -Name Guest | Select-Object -Property SID

How many users have their password required values set to False?

PS C:\Users\Administrator> Get-LocalUser | Where-Object {$_.PasswordRequired -eq $false}

Kết quả là 4 (không có Administrator).

How many local groups exist?

PS C:\Users\Administrator> Get-LocalGroup | Measure-Object -Line

Kết quả là 24.

What command did you use to get the IP address info?

Get-NetIPAddress

How many ports are listed as listening?

PS C:\Users\Administrator> Get-NetTCPConnection | Where-Object {$_.State -eq 'Listen'} | Measure-Object -Line 

Kết quả là 20.

How many patches have been applied?

PS C:\Users\Administrator> Get-HotFix | Measure-Object -Line

Kết quả là 20.

Find the contents of a backup file.

Tìm vị trí của file backup:

PS C:\Users\Administrator> Get-ChildItem -Path C:\ -Filter *.bak* -Recurse

Tìm được ở: C:\Program Files (x86)\Internet Explorer\passwords.bak.txt.

Đọc nội dung:

PS C:\Users\Administrator> Get-Content -Path "C:\Program Files (x86)\Internet Explorer\passwords.bak.txt"
backpassflag

Search for all files containing API_KEY

Get-ChildItem -Path C:\ -Recurse | Select-String -Pattern API_KEY -Context 0,10

Kết quả xuất hiện gần thông báo lỗi

> 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
At line:1 char:42
+ ... ath C:\ -Recurse -File | Select-String -Pattern API_KEY -Context 0,10
+                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Select-String], ArgumentException
    + FullyQualifiedErrorId : ProcessingFile,Microsoft.PowerShell.Commands.SelectStringCommand

What command do you do to list all the running processes?

Get-Process

What is the path of the scheduled task called new-sched-task?

Get-ScheduledTask -TaskName "new-sched-task"

Kết quả: /

Who is the owner of the C:\

Get-Acl -Path C:\

Kết quả: NT SERVICE\TrustedInstaller

Basic Scripting Challenge

Đoạn script bên dưới sẽ in các port đang chạy có trong một file:

$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
     }
 
}

Đuôi của file PowerShell script là ps1.

Cú pháp tạo biến:

$variable_name = value

Cú pháp vòng lặp:

foreach($new_var in $existing_var){}

Có thể thấy, chúng ta sử dụng toán tử -in để kiểm tra xem một port trong file ($port) có trong danh sách các port đang chạy hay không.

Windows cung cấp chương trình Powershell ISE (the Powershell Text Editor) để có thể chỉnh sửa PowerShell script.

Câu lệnh cho phép thực thi PowerShell script:

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted

What file contains the password? and What is the password?

Get-ChildItem -Path "C:\Users\Administrator\Desktop\emails" -Recurse | Select-String password

Kết quả có dòng sau:

Desktop\emails\martha\Doc3M.txt:106:password is johnisalegend99

What files contains an HTTPS link?

Get-ChildItem -Path "C:\Users\Administrator\Desktop\emails" -Recurse | Select-String https

Kết quả có dòng sau:

Desktop\emails\mary\Doc2Mary.txt:5:https://www.howtoworkwell.rand/

Intermediate Scripting

Trong trường hợp host không có Nmap hoặc Python thì ta cần viết script PowerShell.

Ví dụ, viết một script để quét các port cho phép:

  • Chỉ định khoảng IP để scan.
  • Chỉ định khoảng port.
  • Chỉ định loại scan (có thể là TCP connect scan).

Định nghĩa các tham số ở đầu script:

Param(
    [Parameter(Mandatory = $true)]
    [string]$HostName,
 
    [Parameter(Mandatory = $true)]
    [string]$Ports, # '1,2,3' or '1-100'
 
    [Parameter(Mandatory = $true)]
    [string]$Protocol # 'tcp' or 'udp'
)

Hàm tách port:

function ParsePort {
    $PortList = @()
    if ($Ports.Contains(",")) {
        $PortList = $Ports.Split(",")
    }
    elseif ($Ports.Contains("-")) {
        $portBoundaries = $Ports.Split("-")
        $startPort = [int]$portBoundaries[0]
        $endPort = [int]$portBoundaries[1]
        if ($endPort -le $startPort) {
            Write-Output "End port must be greater than start port" 
            exit
        }
        for ($i = $startPort; $i -le $endPort; $i++) { 
            $PortList += $i 
        }
    }
 
    return $PortList
}

Các hàm scan port:

function Scan {
    param (
        [string[]]$PortList
    )
    foreach ($Port in $PortList) {
        if (IsPortOpen $Port) {
            Write-Output "Port $Port is open"
        }
        else {
            Write-Output "Port $Port is closed"
        }
    }
}
 
function IsPortOpen {
    param (
        [string]$Port
    )
    $Socket = $null
    if ($Protocol -eq 'tcp') {
        $Socket = New-Object System.Net.Sockets.TcpClient
    }
    elseif ($Protocol -eq 'udp') {
        $Socket = New-Object System.Net.Sockets.UdpClient
    }
    
    try {
        $Socket.Connect($HostName, $Port)
        $Socket.Close()
        return $true
    }
    catch {
        return $false
    }
}

Gọi sử dụng các hàm trên:

$PortList = ParsePort
Scan $PortList

Câu lệnh thực thi:

PS C:\Users\Administrator\Desktop> .\PortScanner.ps1 -HostName localhost -Ports 130-140 -Protocol tcp

Kết quả là chỉ có port 135 được mở. Mà câu trả lời này lại không đúng.

Tham khảo walkthrough thì thấy ngoài test bằng TCP còn cần test bằng ICMP (ping). Sửa lại hàm IsPortOpen sử dụng Test-NetConnection như sau:

function IsPortOpen {
    param (
        [string]$Port
    )
 
    $Connection = Test-NetConnection -ComputerName $HostName -Port $Port
    return $Connection.TcpTestSucceeded -or $Connection.PingSucceeded
}

Nhớ bỏ tham số $Protocol.

Câu lệnh trở thành:

PS C:\Users\Administrator\Desktop> .\PortScanner.ps1 -HostName localhost -Ports 130-140

Kết quả là cả 11 port từ 130 đến 140 đều được mở.

list
from outgoing([[TryHackMe - Hacking with PowerShell]])
sort file.ctime asc

Resources