สวัสดีครับผู้อ่านทุกท่าน ช่วงที่ผ่านมาผมได้มีโอกาสหมกตัวอยู่กับการเขียนโปรแกรม (หลังจากที่หายไปนาน) ทำให้ผมมีโอกาสได้ไปอ่านบทความที่น่าสนใจมา และอีกทั้งพบว่าเพื่อน ๆ ที่บริษัทหลายท่านไม่รู้จักบัค (โคตะระ) เก่าแก่ตัวนี้ ฮ่า ๆ วันนี้ผมจึงมาเขียนถึงช่องโหว่ที่เรียกว่า “Use After Free” แบบคร่าว ๆ ครับ
(ป.ล. พบในงานยากครับ เนื่องจากงานในปัจจุบันส่วนใหญ่เป็น Web/Mobile Application ซะส่วนใหญ่ครับ ดังนั้นถือว่าอ่าน ฮา ๆ แล้วกันครับบ)
Heap Exploit คืออะไร?
Heap Exploit คือ การโจมตีที่เกิดจากการจัดการหน่วยความจำในส่วนของ heap อย่างไม่เหมาะสม โดย heap เป็นพื้นที่หน่วยความจำที่โปรแกรมสามารถจองและคืนได้ตามต้องการผ่านฟังก์ชัน เช่น malloc() และ free() ใน C หรือ new และ delete ใน C++ การจัดสรรพื้นที่ใน heap ทำให้เราสามารถจัดการข้อมูลที่ต้องการใช้งานได้อย่างยืดหยุ่น แต่หากการจัดการนี้ไม่ถูกต้อง อาจเกิดช่องโหว่ที่ผู้ไม่ประสงค์ดีสามารถใช้ประโยชน์ได้ เช่น การเขียนทับข้อมูลสำคัญ (Heap Overflow) หรือการใช้ข้อมูลที่ถูกคืนแล้ว (Use After Free) ซึ่งสามารถนำไปสู่การควบคุมโปรแกรมหรือการเรียกใช้คำสั่งโดยไม่ได้รับอนุญาตได้
Use After Free (UAF) คืออะไร?
“Use After Free” หรือย่อว่า UAF ซึ่งเป็นหนึ่งในชนิดของ Heap Exploit ที่มักพบในโปรแกรมที่ใช้ภาษาการเขียนโปรแกรมที่ไม่ได้มีการจัดการหน่วยความจำอย่างปลอดภัย (Memory-Unsafe) เช่น C และ C++ โดยปัญหานี้เกิดจากการใช้หน่วยความจำที่ได้ถูกจัดสรรหรือจองไว้แล้ว (allocation) หลังจากที่มันได้ถูกคืน (free) กลับไปให้ระบบครับ ซึ่งอาจนำไปสู่การโจมตีจากผู้ไม่หวังดี เช่น การรันคำสั่งระยะไกล (Remote Code Execution) หรือการยกระดับสิทธิ์ (Privilege Escalation)
ลองนึกภาพตามครับ เมื่อโปรแกรมจองพื้นที่ใน heap สำหรับการเก็บข้อมูล มันจะได้รับที่อยู่ของหน่วยความจำ (pointer) มาทำงาน การจองพื้นที่แบบนี้เกิดขึ้นผ่านฟังก์ชันเช่น malloc() ใน C หรือ new ใน C++ แต่เมื่อหน่วยความจำที่ถูกจองไม่จำเป็นต้องใช้อีกแล้ว นักพัฒนาจำเป็นต้องใช้ฟังก์ชัน free() ใน C หรือ delete ใน C++ เพื่อคืนหน่วยความจำกลับสู่ระบบ อย่างไรก็ตาม ถ้าโปรแกรมยังคงใช้ pointer นั้นอยู่หลังจากที่หน่วยความจำได้ถูกคืนแล้ว มันก็จะกลายเป็น “Use After Free” ครับ
ตัวอย่างการเกิด Use After Free
ลองมาดูโค้ดตัวอย่างภาษา C ครับ
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
typedef struct string {
unsigned length;
char *data;
} string;
int main() {
struct string* s = malloc(sizeof(string));
puts("Length:");
scanf("%u", &s->length);
s->data = malloc(s->length + 1);
memset(s->data, 0, s->length + 1);
puts("Data:");
read(0, s->data, s->length);
free(s->data);
free(s);
char *s2 = malloc(16);
memset(s2, 0, 16);
puts("More data:");
read(0, s2, 15);
// ใช้ s ที่ได้ถูก free ไปแล้ว = โอกาสเกิด UAF
puts(s->data);
return 0;
}
ในตัวอย่างนี้ เรามีโครงสร้างข้อมูลที่เก็บความยาวและข้อมูลของสตริงอยู่ เราได้จองพื้นที่ใน heap สำหรับเก็บข้อมูลนี้ ทำการอ่านและเก็บข้อมูลลงไป จากนั้นก็ทำการ free หน่วยความจำเหล่านั้น แต่ต่อมาในโค้ดกลับมีการใช้งานตัวแปร s ที่ถูกคืนไปแล้ว ทำให้เกิด Use After Free ซึ่งอาจจะทำให้ข้อมูลที่ได้จากการใช้งานนั้นผิดเพี้ยนหรือถูกโจมตีโดยผู้ไม่ประสงค์ดีได้ครับ
การโจมตี Use After Free ในโลกจริง
การโจมตีที่ใช้ช่องโหว่ UAF ไม่ได้มีแค่ในโค้ดตัวอย่างง่าย ๆ เท่านั้น แต่ในซอฟต์แวร์ขนาดใหญ่ อย่างพวก Browser หรือ OS ที่ใช้กันในปัจจุบันก็พบได้เช่นกัน ยกตัวอย่างเช่น ช่องโหว่ CVE-2022–3910 หรือ CVE-2024–26581 ที่พบใน Linux Kernel ซึ่งทำให้ผู้ไม่ประสงค์ดีสามารถยกระดับสิทธิ์ได้ครับ
นอกจากนี้ ยังมีช่องโหว่ UAF ในเบราว์เซอร์ที่ใช้กันแพร่หลาย เช่น Google Chrome ซึ่งถูกค้นพบหลายครั้งใน component ต่าง ๆ ของเบราว์เซอร์ การโจมตีเหล่านี้สามารถทำให้ผู้ไม่ประสงค์ดีเข้าถึงข้อมูลที่สำคัญของผู้ใช้ หรือแม้กระทั่งยึดครองการควบคุมระบบได้ การโจมตีผ่านช่องโหว่ UAF เป็นปัญหาที่เกิดขึ้นอย่างต่อเนื่องในซอฟต์แวร์ที่ต้องจัดการหน่วยความจำเอง และเป็นช่องโหว่ที่ถูกโจมตีบ่อยครั้ง
ผลกระทบจาก Use After Free
ช่องโหว่ UAF อาจมีผลกระทบได้หลายรูปแบบ ตั้งแต่การทำให้โปรแกรมหยุดทำงานไปจนถึงการที่ผู้ไม่ประสงค์ดีสามารถเข้าควบคุมโปรแกรมได้ทั้งหมด ข้อมูลที่เก็บในหน่วยความจำที่ถูกใช้หลังการคืน อาจถูกแก้ไข ซึ่งนำไปสู่การที่โปรแกรมทำงานผิดพลาดหรือข้อมูลสำคัญถูกขโมย ผลกระทบที่พบบ่อยได้แก่ การรั่วไหลของข้อมูล การหยุดทำงานของแอปพลิเคชัน การยกระดับสิทธิ์ การเลี่ยงผ่านการยืนยันตัวตน การเสียหายของข้อมูล และการรันโค้ดระยะไกลครับ
ตัวอย่างของการโจมตีที่มีผลกระทบอย่างรุนแรง เช่น การที่ผู้ไม่ประสงค์ดีสามารถใช้ช่องโหว่ UAF เพื่อเข้าถึง session ของผู้ใช้ในเบราว์เซอร์ หรือยึดระบบผ่านการโจมตี Remote Code Execution ซึ่งทำให้ผู้ไม่ประสงค์ดีสามารถควบคุมระบบทั้งหมดได้ นอกจากนี้ ช่องโหว่ UAF ยังถูกใช้ในการโจมตีเพื่อเจาะข้อมูลสำคัญขององค์กร ทำให้การป้องกันช่องโหว่เหล่านี้เป็นสิ่งที่สำคัญมาก
การป้องกัน Use After Free
วิธีหนึ่งที่ดีในการป้องกัน UAF ก็คือการตั้งค่า pointer ให้เป็น NULL หลังจากที่ได้ทำการ free หน่วยความจำนั้นแล้วครับ การ dereference pointer ที่เป็น NULL จะทำให้โปรแกรมหยุดทำงานในทันที ซึ่งดีกว่าการมีบั๊ก UAF ที่ทำให้เกิดการทำงานผิดพลาดโดยไม่แจ้งเตือนใด ๆ
เครื่องมือช่วยป้องกัน
นอกจากนี้ เรายังสามารถใช้ smart pointers ในภาษา C++ ซึ่งจะช่วยให้การจัดการหน่วยความจำง่ายขึ้น และช่วยลดความเสี่ยงของ UAF ได้ เนื่องจาก smart pointers จะช่วยจัดการการคืนหน่วยความจำให้เราโดยอัตโนมัติครับ นอกจากนี้ การใช้ เครื่องมือ Static Analysis เช่น Clang Static Analyzer Coverity หรือ เครื่องมือ Dynamic Analysis เช่น Address Sanitizer (ASan) เพื่อทำการตรวจสอบโค้ดก็เป็นอีกวิธีหนึ่งที่ดีในการค้นหาช่องโหว่ UAF ก่อนที่โค้ดจะถูกใช้งานจริง
อีกทั้งการใช้ Memory Allocator ที่มีการตรวจสอบการใช้งานหน่วยความจำอย่างเข้มงวด เช่น jemalloc หรือ tcmalloc ก็เป็นอีกทางเลือกหนึ่งที่ช่วยป้องกันปัญหาการใช้หน่วยความจำผิดพลาด โดยตัวจัดการหน่วยความจำเหล่านี้มีการตรวจสอบและจัดการหน่วยความจำอย่างมีประสิทธิภาพ ทำให้ลดความเสี่ยงในการเกิดช่องโหว่ UAF ได้ครับ
สรุปช่องโหว่ Use After Free
เป็นปัญหาที่เกิดจากการจัดการหน่วยความจำอย่างไม่เหมาะสมในภาษาที่ไม่มีการจัดการหน่วยความจำแบบอัตโนมัติ ถ้าไม่ได้ระมัดระวังในการจัดการการคืนหน่วยความจำ โปรแกรมอาจจะทำงานผิดพลาดหรือเปิดช่องให้ผู้ไม่ประสงค์ดีเข้ามาโจมตีได้ การป้องกันที่ดีคือการตั้ง pointer เป็น NULL ทันทีหลังจากการ free และการใช้ smart pointers เพื่อช่วยจัดการหน่วยความจำให้ปลอดภัยมากขึ้น นอกจากนี้การใช้เครื่องมืออย่าง Address Sanitizer และ Memory Allocator ที่มีความเข้มงวดก็เป็นอีกทางเลือกที่ช่วยให้โปรแกรมของเรามีความปลอดภัยมากขึ้น
หวังว่าบทความนี้จะช่วยให้ทุกท่านที่หลงเข้ามาอ่าน ได้เข้าใจ Use After Free และวิธีการป้องกันมันได้ดีขึ้นนะครับ
หากผิดถูกยังไงกระผมขออภัยมา ณ ที่นี้ด้วยครับบ
Reference
- https://ctf101.org/binary-exploitation/overview/
- https://learn.snyk.io/lesson/use-after-free/
- https://www.inetms.co.th/article-131869-linux-kernel-%E0%B8%9E%E0%B8%9A%E0%B8%8A%E0%B9%88%E0%B8%AD%E0%B8%87%E0%B9%82%E0%B8%AB%E0%B8%A7%E0%B9%88-use-after-free.html
— https://nvd.nist.gov/vuln/detail/CVE-2022-3910 - https://github.com/google/security-research/blob/master/pocs/linux/kernelctf/CVE-2024-26581_lts_cos_mitigation/docs/exploit.md
- https://valgrind.org/downloads/
- https://wiki.ubuntu.com/Valgrind
- https://devblogs.microsoft.com/cppblog/asan-for-windows-x64-and-debug-build-support/