【THM】Hacking with PowerShell(Powershell脚本基础)-学习
本文相关的TryHackMe实验房间链接:https://tryhackme.com/room/powershell
通过学习相关知识点:了解PowerShell攻击以及学习PowerShell脚本的基础知识。
PowerShell教程参考链接(不权威):https://www.yiibai.com/powershell
Powershell官方文档链接:https://learn.microsoft.com/en-us/powershell/scripting/how-to-use-docs?view=powershell-7.3
简介
在本文相关的实验中,我们将探讨以下概念:
- 什么是 Powershell 及其工作原理
- 基本的 Powershell 命令
- 使用 Powershell 枚举Windows信息
- Powershell脚本基础
我们将使用以下凭据 通过RDP来控制本地攻击机访问靶机实例(或者直接在Tryhackme实验房间页面-通过浏览器访问靶机):
- Username:
Administrator
- Password:
BHN2UVw0Q
#xfreerdp /u:Administrator /p:BHN2UVw0Q /cert:ignore /v:MACHINE_IP
注意:目标机器不响应 ping (ICMP)命令,我们将通过TryHackMe相关的实验房间页面部署虚拟靶机,这可能需要几分钟时间。
什么是 Powershell
Powershell 是使用 .NET 框架构建的 Windows 脚本语言和 Windows shell 环境。
Windows 允许 Powershell 直接从其 shell 界面执行 .NET 函数,大多数 Powershell 命令(被称为 cmdlet)就是用 .NET 编写的。
具体而言:cmdlet 是在 PowerShell 环境中使用的一种轻量级命令。
不同于其他脚本语言和 shell 环境,cmdlet(Powershell 命令) 的输出结果是对象——这使得 Powershell 在某种程度上有种面向对象的概念;这意味着运行 cmdlet (Powershell命令)将允许我们对输出对象执行操作(也就是说将输出从一个cmdlet传递到另一个cmdlet会很方便)。
cmdlet(Powershell 命令)的正常书写格式是使用“动词-名词(Verb-Noun) ”形式来表示,如:用于列举命令的cmdlet是Get-Command
。
常用的Powershell命令动词(Verbs)包括:
- Get
- Start
- Stop
- Read
- Write
- New
- Out
访问以下链接,可查看合法的Powershell命令动词的完整列表:
答题
基本的 Powershell 命令
现在我们已经了解了 cmdlet(Powershell命令) 的基本工作原理 - 让我们继续探索如何使用它们!Get-Command
和 Get-Help
将有助于我们更好地理解如何使用Powershell命令。
使用Get-Help
命令
Get-Help
命令将显示 cmdlet 的相关信息,如果要获取某个特定命令的帮助信息,请运行以下命令:Get-Help Command-Name
我们还可以通过传入-examples
参数来进一步获取某个特定命令的相关信息,传入-examples
参数将返回如下输出结果:
使用Get-Command
命令
Get-Command
命令可以获取当前计算机上已经安装的所有cmdlet (Powershell命令) 列表,这个 cmdlet(Powershell命令) 的伟大之处在于 它将允许使用如下的模式匹配:Get-Command Verb-*
或者 Get-Command *-Noun
。(Verb-动词,Noun-名词)
运行 Get-Command New-*
命令 将允许我们查看以动词New开头的所有 cmdlet(Powershell命令) :
针对对象执行操作
在上一小节中,我们了解到每个 cmdlet(Powershell命令) 的输出都是一个对象,如果我们想要对Powershell命令的输出结果进行操作,我们还需要弄清楚一些事情:
- 将输出传递给其他 cmdlet
- 使用特定对象 cmdlet 提取信息
使用管道 ("|"
) 符号可将输出结果从一个cmdlet(Powershell命令)传递到另一个cmdlet(Powershell命令)。
Powershell 与其他 shell 相比的主要区别在于:它不是将文本或字符串传递给管道后的命令,而是将对象传递给下一个cmdlet(Powershell命令)。与面向对象框架中的每个对象一样,Powershell中的对象也将包含方法和属性,我们可以将方法视为可应用于 cmdlet 输出的函数,将属性视为 cmdlet 输出中的变量。
如果要查看详细信息,我们可以将 cmdlet(Powershell命令) 的输出传递给 Get-Member
cmdlet:Verb-Noun | Get-Member
运行命令以查看 Get-Command
成员的示例是:Get-Command | Get-Member -MemberType Method
关于上面Powershell命令中的参数,我们可以选择方法(Method)或者属性(Property)进行查看。
基于前一个 cmdlet 创建对象
操作对象的一种方法是从 前一个cmdlet的输出结果中提取属性并创建一个新对象,这是使用 Select-Object
cmdlet 完成的。
以下是一个示例:列举目录并仅选择显示模式(Mode)、名称(Name)。
我们还可以使用以下参数来选择显示其他特定信息:
- first - 获取第一个 x 对象
- last - 获取最后一个 x 对象
- unique - 显示独特的对象
- skip - 跳过 x 个对象
过滤对象
当我们检索输出对象时,可能会希望显示一些可以与特定值匹配的对象,因此我们可以使用 Where-Object
命令——以根据属性值来执行过滤对象的操作。
使用此类 cmdlet 的一般格式是:
Verb-Noun | Where-Object -Property PropertyName -operator Value
Verb-Noun | Where-Object {$_.PropertyName -operator Value}
上面的第二个格式将使用$_
运算符循环访问传递给 Where-Object
cmdlet 的每个对象。
注意:Powershell 非常敏感,因此请确保不要在命令周围加上引号!
以上命令中的 -operator
可以取自以下几个运算符:
- -Contains:如果属性值中的任何项目都与指定值完全匹配,则
Where-Object
cmdlet会使用此参数从集合中获取对象。 - -EQ:如果属性的值与指定的值相同,则
Where-Object
cmdlet会使用此参数获取对象。 - -GT:如果属性的值大于指定值,则
Where-Object
cmdlet会使用此参数获取对象。
关于完整的运算符(operator)列表--请参考以下链接:
以下为一个示例:检查并显示已停止的进程。
对输出的对象进行排序
当 cmdlet(Powershell命令) 输出大量信息时,就可能需要对其进行排序以便我们更有效地提取信息,我们可以将 cmdlet(Powershell命令) 的输出结果通过管道符号("|"
)连接到Sort-Object
cmdlet 以此来执行排序操作。
此类命令的格式是:Verb-Noun | Sort-Object
以下是对目录列表进行排序的示例:
答题
现在我们已经了解了关于 Powershell 工作原理的基础知识,让我们尝试应用这些知识来使用Powershell命令并以此回答下面的问题。
注意:此处需要在实验靶机中执行Powershell命令。
先通过以下命令连接并访问目标机器:
#xfreerdp /u:Administrator /p:BHN2UVw0Q /cert:ignore /v:MACHINE_IP
#添加参数 /workarea 可以使打开的RDP窗口最大化
xfreerdp /u:Administrator /p:BHN2UVw0Q /cert:ignore /v:10.10.182.215
打开实验靶机的Powershell界面,开始答题:
问题:文件“interesting-file.txt”的位置是什么?
Get-ChildItem -Path C:\ -Include interesting-file.* -File -Recurse -ErrorAction SilentlyContinue
#Get-ChildItem 在一个或多个位置获取项目和子项目——获取目录列表
#-Path 该参数用于指定一个或多个位置的路径。默认位置是当前目录(.符号),允许使用通配符。
#-Include 该参数会将属性指定为字符串数组,-Include参数的值限定在Path参数所对应的路径下,此处可输入模式或路径元素,例如*.txt。
#-File 该参数用于获取文件列表
#-Recurse 递归,该参数用于获取指定位置中的项目以及该位置的所有子项目
#-ErrorAction SilentlyContinue 不显示错误消息
C:\Program Files
问题:查看文件“interesting-file.txt”的内容
Get-Content -Path 'C:\Program Files\interesting-file.txt.txt'
#Get-Content 用于在指定位置获取项目的内容,gc、cat和type是此cmdlet的别名。
notsointerestingcontent
问题:系统上安装了多少个 cmdlet(仅 cmdlet,不包括函数和别名)?
Get-Command | Where-Object -Property CommandType -eq Cmdlet | measure
#Get-Command 用于获取计算机系统上安装的所有命令
#measure 检索有关资源的统计信息
6638
问题:interesting-file.txt 的 MD5 散列是什么?
Get-FileHash 'C:\Program Files\interesting-file.txt.txt' -Algorithm MD5 | Format-List
#Get-FileHash 文件路径 -Algorithm 校验的Hash值类型| Format-List
#Algorithm 翻译为算法
#Get-FileHash命令的官方文档链接:https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-filehash?view=powershell-7.3&viewFallbackFrom=powershell-6
49A586A2A9456226F8A1B4CEC6FAB329
问题:获取当前工作目录的命令是什么?
Get-Location
#获取当前工作目录
Get-Location
问题:路径“C:\Users\Administrator\Documents\Passwords”是否存在(Y/N)?
Get-Location "C:\Users\Administrator\Documents\Passwords"
#验证路径“C:\Users\Administrator\Documents\Passwords”是否存在
N (路径“C:\Users\Administrator\Documents\Passwords”不存在)
问题:你将使用什么命令向 Web 服务器发出请求?
Invoke-WebRequest
#Invoke-WebRequest命令的官方文档链接:https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-7.3&viewFallbackFrom=powershell-7.1
Invoke-WebRequest
问题:解码目标Windows机器上的Base64编码文件 b64.txt 得到flag。
Get-ChildItem -Path C:/ -Include *b64.txt* -Recurse -File
certutil -decode "C:\Users\Administrator\Desktop\b64.txt" out.txt
Get-Content out.txt
#certutil官方文档链接:https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/certutil
ihopeyoudidthisonwindows
使用 Powershell 枚举信息
当我们获得对任何机器的初始访问权限之后,第一步操作往往是枚举信息,我们将尝试列举以下内容:
- users——用户
- basic networking information——基本网络信息
- file permissions——文件权限
- registry permissions——注册表权限
- scheduled and running tasks——计划和运行任务
- insecure files——不安全的文件
答题
此处需要我们在目标机器上使用 Powershell 命令枚举信息并回答以下问题!
问题:机器上有多少用户?
Get-LocalUser
共有5个用户
问题:这个SID(S-1-5-21-1394777289-3961777894-1791813945-501)属于哪个本地用户?
Get-LocalUser -SID "S-1-5-21-1394777289-3961777894-1791813945-501"
Guest
问题:有多少用户的密码要求值被设置为 False?
Get-LocalUser | Where-Object -Property PasswordRequired -Match false
4
问题:存在多少本地组?
Get-LocalGroup | measure
#measure 检索有关资源的统计信息
24
问题:使用什么命令能够获取 IP 地址信息?
Get-NetIPAddress
Get-NetIPAddress
问题:有多少端口为侦听状态?
Get-NetTCPconnection -State Listen
Get-NetTCPconnection -State Listen | measure
#measure 检索有关资源的统计信息
20
问题:侦听端口 445 的本地端口的远程地址是什么?
Get-NetTCPconnection -State Listen -LocalPort 445
::
问题:当前系统应用了多少补丁?
Get-Hotfix | measure
#Hotfix 翻译为修补程序(补丁)
#measure 检索有关资源的统计信息
20个补丁
问题:ID为KB4023834的补丁是什么时候安装的?
Get-Hotfix -Id KB4023834
6/15/2017 12:00:00 AM
问题:查看备份文件的内容。
Get-ChildItem -Path C:\ -Include *.bak* -File -Recurse -ErrorAction SilentlyContinue
Get-Content "C:\Program Files (x86)\Internet Explorer\passwords.bak.txt"
backpassflag
问题:搜索所有包含 API_KEY 的文件,并找到API_KEY对应的值。
Get-ChildItem C:\* -Recurse | Select-String -pattern API_KEY
API_KEY=fakekey123
问题:执行什么命令可以列出所有正在运行的进程?
Get-Process
Get-Process
问题:名为new-sched-task的定时任务的路径是什么?
Get-Scheduledtask -TaskName new-sched-task
\(写/也可以)
问题:谁是 C:\ 的所有者
Get-Acl C:\
NT SERVICE\TrustedInstaller
编写和执行基本的 Powershell 脚本
本小节我们将尝试编写和执行Powershell脚本来完成一些更复杂和更强大的操作。
在此处我们将使用PowerShell ISE(它是 Powershell 文本编辑器)编写Powershell脚本。
为了更好地展示此处的脚本示例,让我们假设一个特定的场景:给定一个包含端口列表的文本文件,尝试检查该文本文件中的端口列表 并得出此列表中实际处于侦听状态的端口号。
我们将使用 Powershell ISE 在靶机的桌面上打开以下listening-ports.ps1脚本(Powershell 脚本通常使用的文件扩展名为.ps1)。
#listening-ports.ps1
$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
}
}
在以上Powershell脚本的第一行,我们将尝试获得当前目标系统上所有实际处于侦听状态的端口号,我们可以使用 Get-NetTCPConnection
cmdlet 来执行此操作;然后我们将该 cmdlet 的输出结果保存到一个变量中,创建变量的命令形式将如下所示:
$variable_name = value
在以上Powershell脚本的第二行,我们将从一个文本文件中读取端口列表,我们可以使用 Get-Content
cmdlet 来执行此操作;同样,我们会将输出结果存储在一个变量中,以上Powershell脚本接下来的操作是 遍历前述文本文件内容中的所有端口号以查看哪些端口实际处于侦听状态——要遍历文本文件中的所有端口号,我们将使用以下形式的命令:
foreach($new_var in $existing_var){}
这个特定的foreach代码块可用于循环访问一组对象,一旦我们得到了文本文件内容中的每个单独的端口号,我们就可以检查这些单独的端口号 是否实际处于侦听状态;在此处,我们并没有选择执行一个新的 for 循环来完成操作,而是使用带有-in
运算符的 if 语句来检查每个单独的端口号是否具有指定对象的 LocalPort
属性,如果具有该属性 则说明对应的端口号实际处于侦听状态。
关于if语句中的比较运算符列表:
要运行以上的listening-ports.ps1 脚本,我们可以在Windows终端中调用脚本路径进行执行或者用Powershell ISE打开以上脚本并单击ISE编辑器中的绿色按钮:
编写Powershell脚本可能有点困难,以下链接中的资源可供参考:https://learnxinyminutes.com/docs/powershell/
答题
实验靶机的桌面上有一个emails 文件夹,该文件夹包含了 John、Martha 和 Mary 发送给彼此(和他们自己)的电子邮件的副本,根据这些电子邮件副本的内容回答以下问题(尽量不要直接打开电子邮件副本文件,请尝试编写Powershell以完成答题)。
访问实验靶机并打开PowerShell ISE:
问题:哪些文件包含password字符?password对应的内容具体是什么?
$path = "C:\Users\Administrator\Desktop\emails\*"
$string_pattern = "password"
$command = Get-ChildItem -Path $path -Recurse | Select-String -Pattern $String_pattern
echo $command
Doc3M
johnisalegend99
问题:哪些文件包含 HTTPS 链接?
$path = "C:\Users\Administrator\Desktop\emails\*"
$string_pattern = "HTTP"
$command = Get-ChildItem -Path $path -Recurse | Select-String -Pattern $String_pattern
echo $command
Doc2Mary
中级Powershell脚本
现在我们已经对Powershell脚本的工作原理有了一些了解 - 让我们尝试一些更有趣的东西。
当成功获得目标机器的初始访问权限之后,有时在目标机上可能没有 nmap 和 python 这样的实用程序可供我们使用,因此我们就需要编写脚本 来完成一些非常基础的操作。
我们可以尝试使用 Powershell 来编写一个简单的端口扫描器,以下是一般方法:
- 确定要扫描的 IP 范围(在这种情况下它将是本地主机),我们可以以任何想要的方式提供输入;
- 确定要扫描的端口范围;
- 确定要运行的扫描类型(在本例中为简单的 TCP 连接扫描)。
答题
使用原始 TCP 套接字(raw socket)或 Test-NetConnection
问题:在端口 130 到 140(包括这两个)之间能找到多少个开放端口?
for($i=130; $i -le 140; $i++){ Test-NetConnection localhost -Port $i }
#扫描端口130~140(包括这两个端口号)以查找开放端口
#-le length equal 循环中的表达式条件为等于140
1