Heap and Address Space Layout Randomization
Contents
Cuối cùng thì mình cũng hoàn thành xong cái blog này. Mặc dù chưa được đẹp lắm nhưng mình khá hài lòng về nó.
Giờ chỉ còn một việc nữa là đưa các bài viết từ trang wordpress cũ di cư sang bên này thôi. Bắt đầu từ bài đầu tiên nào!
1. Address Space Layout Randomization (ASLR):
- ASLR là một kỹ thuật giúp cho địa chỉ của các phân vùng bộ nhớ thay đổi ngẫu nhiên với mỗi lần chạy.
- Khi không bật ASLR thì các phân vùng bộ nhớ khi chạy chương trình sẽ có địa chỉ như sau:
{: .mx-auto.d-block :}
- Khi bật ASLR lên thì địa chỉ sẽ thay đổi:
{: .mx-auto.d-block :}
- Tuy nhiên trên Linux thì không phải phân vùng nào cũng được random địa chỉ. Nhìn vào hình trên, ta chỉ thấy địa chỉ của Heap, Stack và Libc là thay đổi. Các phân vùng khác như: .text, .rodata, .got, … đều có địa chỉ giữ nguyên.
- Để tận dụng tối đa hiệu quả của ASLR, ta có thể compile binary với flag -pie -fPIE. Khi đó binary của chúng ta được gọi là PIE (Position Independent Executable)
- Position Independent Executable là các file thực thi được compile sao cho chúng có thể chạy được mà không cần quan tâm đến địa chỉ. Các shared library (thư viện liên kết động) thường được compile như thế này.
- Khi chạy PIE trong Linux, địa chỉ của tất cả các phân vùng bộ nhớ sẽ được random.
- Để bypass ASLR, người ta thường cố gắng leak địa chỉ của bộ nhớ. Khi leak được 1 địa chỉ, ta có thể tính toán tất cả các địa chỉ khác thông qua offset (offset luôn cố định dù địa chỉ bị random)
2. Heap:
- Heap là vùng nhớ dùng cho cấp phát động vào runtime. Việc cấp phát này được thực hiện bởi người lập trình qua các câu lệnh như malloc(), free(),…
- Mỗi lần dùng câu lệnh malloc(), ta sẽ được cấp một heap chunk. Cấu trúc của heap chunk như sau:
{: .mx-auto.d-block :}
- Pointer mà malloc() trả về cho ta trỏ đến phần đầu của phân vùng Data (như trong hình).
- Trái với Stack, heap đi xuống vùng có địa chỉ cao hơn.
{: .mx-auto.d-block :}
3. Heap exploitation:
- Heap overflow: Cũng là tràn bộ nhớ như stack overflow
- Use after free (UAF): Khi vùng nhớ trên heap đã được giải phóng nhưng vẫn còn pointer trỏ đến vùng nhớ đó, và chương trình vẫn sử dụng dữ liệu được trỏ đến bởi pointer này một cách bình thường.
- Ví dụ:
{: .mx-auto.d-block :}
- Ở struct toystr có pointer message trỏ đến một hàm. Giả sử sau khi giải phóng vùng nhớ của một struct toystr, chương trình vẫn sử dụng 1 con pointer trỏ đến vùng nhớ đó. Ta có thể tìm cách cấp phát cho mình một vùng nhớ thuộc struct person tại địa chỉ ấy, sau đó ghi giá trị vào biến favorite_num. Như vậy ta có thể điều khiển địa chỉ của hàm mà con trỏ message trỏ đến –> có thể gọi bất kỳ hàm nào