NT521 - Lập trình an toàn &
Khai thác lỗ hổng phần mềm
Trường ĐH CNTT – ĐHQG TP. HCM
University of Information Technology (UIT), VNU-HCM
Buổi 09
2
Off-by-one & Return-to-lib-c
University of Information Technology (UIT), VNU-HCM
Nội dung
Tấn công Off-by-one
Tấn công Return-to-lib-c
3
University of Information Technology (UIT), VNU-HCM
Tổng quan
Khai thác lỗ hổng tràn bộ đệm - buffer overflow:
Trường hợp tưởng:
khả năng kiểm soát return addr: không dùng stack
canary, thể ghi đè đến vị trí return addr
thể truyền shellcode vào stack thực thi: -z execstack
Các trường hợp ràng buộc hơn?
Off-by-one
Giới hạn kích thước buffer thể bị ghi đè, không đủ để ghi
đè return addr
Return-to-libc
Shellcode cần viết quá phức tạp hoặc quá dài, stack không
cho phép thực thi code
ROP (Return Oriented Programming)
Stack không cho phép thực thi
4
University of Information Technology (UIT), VNU-HCM
5
Tấn công
Off-by-one
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Vì sao?
Tấn công tràn bộ đệm trên stack đôi khi không cho phép
ghi đè trực tiếp địa chỉ trả về.
6
Cần tấn công kiểu gián tiếp
void bar(){
char buf[256];
int i;
for(i = 0; i <= 256; i++)
buf[i] = getchar();
// other statements…
}
void foo(){
bar();
}
vấn đề với đoạn code trên?
Dùng <= thay <
thể nhập tự thứ 257, nhưng chưa đủ để ghi đè được
return addr
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Ví dụ
Luồng thực thi foo() bar()
buf được thiết kế độ dài 256
bytes 256 tự.
Giả sử buf nằm liền kề vị trí lưu
saved ebp.
Nếu thêm 1 tự được ghi
thêm trong stack?
Saved ebp của bar sẽ thay đổi
Nếu saved ebp của bar thay đổi?
Khi thực thi xong bar, foo sẽ không
tìm được đúng stack frame của mình
foo không tìm được biến cục bộ
return addr
7
Return addr of foo
Saved ebp
Local variables of
foo
Return addr of bar
Saved ebp
buf
Lower
addr
Higher
addr
Other local
variables of bar
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Ví dụ (2)
Nếu byte thấp nhất trong saved
ebp của bar thay đổi thành giá trị
nhỏ hơn, dụ 0x00?
Saved ebp sẽ trỏ đến 1 vị trí
nào đó thấp n stack frame
gốc của foo
8
??
1 địa chỉ thấp
hơn stack frame
của foo
Return addr of foo
Saved ebp
Local variables of
foo
Return addr of bar
Saved ebp
buf
Other local
variables of bar
Lower
addr
Higher
addr
xx
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Ví dụ (3)
Ý tưởng:
Ghi 1 stack frame giả vào bộ nhớ
đệm để giả mạo stack frame của
foo.
Điều khiển được các biến cục bộ
của foo xem như bản điều
khiển được foo.
Ghi đè byte cuối của saved ebp
của bar để trỏ về stack frame giả.
9
Return addr of foo
Saved ebp
Local variables of
foo
Return addr of bar
Saved ebp
Higher
addr
xx
Return addr of foo
Saved ebp
Local variables of
foo
buf
Stack frame giả
cho foo
Other local
variables of bar
Lower
addr
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Ví dụ (4)
Thậm chí tốt n nếu attacker 1 return
addr chủ đích bên cạnh stack frame
giả.
thể điều hướng sau khi thực thi xong
foo.
thể khai thác như thế nào?
Inject code
Gán return address trong stack frame giả
của foo thành địa chỉ đoạn code muốn
thực thi.
10
Return addr of foo
Saved ebp
Local variables of
foo
Return addr of bar
Saved ebp
Other local
variables of bar
Lower
addr
Higher
addr
xx
Return addr of foo
Saved ebp
Local variables of
foo
buf
Stack frame giả
cho foo
Injected code
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Ví dụ (5)
Kết luận về dụ:
Lỗi lập trình trong việc xác định giới hạn
Dùng <= thay cho < gán giá trị cho ô nhớ nằm ngoài mảng
Nếu buffer nằm gần saved ebp, tấn công Off-by-one
thể cho phép ghi đè saved ebp.
Kẻ tấn công sau đó thể thay đổi saved ebp để trỏ đến
1 stack frame gi.
Với stack frame giả, kẻ tấn công thể kiểm soát return
addr, từ đó kiểm soát luồng thực thi.
11
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Tổng kết
Một số trường hợp truy xuất con trỏ không chính xác thể
cho phép ghi đè trực tiếp hoặc gián tiếp các cấu trúc/dữ liệu
quan trọng, bao gồm return addr.
Các dạng tấn công vào các lỗ hổng này rất khó ngăn chặn.
12
void receive(int socket) {
char buf[MAX];
int nbytes = recv(socket, buf, sizeof(buf), 0);
buf[nbytes] = '\0’;
...
}
Một dụ khác thể bị tấn công off-by-one:
University of Information Technology (UIT), VNU-HCM
13
Tấn công
Return-to-libc
University of Information Technology (UIT), VNU-HCM
Tấn công Return-to-lib-c: Vì sao?
Tên gọi khác: Tấn công Arc-injection
Ngữ cảnh: việc truyền code thực thi (shellcode) đôi khi khó
khăn trong khai thác lỗ hổng buffer overflow.
Shellcode quá dài không để được trong buffer.
Shellcode quá phức tạp
Trên stack không cho phép thực thi code
14
Tận dụng code sẵn trong chương trình, hay cụ thể trong các
thư viện C (libc)
Libc cung cấp các macro, các định nghĩa kiểu dữ liệu các hàm cho các tác vụ
phổ biến như: xử chuỗi, tính toán toán học, xử input/output, cấp phát bộ
nhớ,…
dụ: printf(), scanf(), system(),
Mục tiêu: Ghi đè return address để điều hướng luồng chương
trinh đến c đoạn code sẵn trong bộ nhớ.
University of Information Technology (UIT), VNU-HCM
Tấn công Return-to-lib-c: Ví dụ
15
int main(int argc, char *argv[]){
char buf[4];
strcpy(buf, argv[1]);
return 0;
}
vấn đề với đoạn code trên?
Dùng strcpy là 1 hàm sao chép chuỗi nhưng không có cơ chế kiểm tra sự phù
hợp độ dài giữa nguồn (argv[1]) và đích (buf).
Mục tiêu: Khai thác lỗ hổng buffer overflow để mở shell tương tác
không truyền code thực thi.
Giả sử biên dịch với option -z noexestack để ngăn thực thi trên code
Cho đoạn chương trình dụ:
University of Information Technology (UIT), VNU-HCM
Tấn công Return-to-lib-c: Ví dụ (2)
16
Ý tưởng
thể mở shell bằng cách gọi hàm system(“/bin/bash”).
system() 1 hàm libc.
Tham số của hàm command muốn thực thi
Như thế nào?
Đổi return address thành địa chỉ của hàm system
Gán tham số đầu tiên thanh địa chỉ chuỗi “/bin/bash”
Cho đoạn chương trình dụ:
int main(int argc, char *argv[]){
char buf[4];
strcpy(buf, argv[1]);
return 0;
}
University of Information Technology (UIT), VNU-HCM
Tấn công Return-to-lib-c: Ví dụ (2)
17
Cho đoạn chương trình dụ:
Other data in stack
Return addr of main
saved ebp
buf
Stack
frame
của
main
Stack trước khai thác
Address of system
saved ebp
buf
Stack
frame
của
main
Stack sau khai thác
Return addr of system
Addr of “/bin/bash”
int main(int argc, char *argv[]){
char buf[4];
strcpy(buf, argv[1]);
return 0;
}
??
Tham số và
stack frame giả
cho system
University of Information Technology (UIT), VNU-HCM
Tấn công Return-to-lib-c: Ví dụ (3)
18
Địa chỉ của hàm system?
Debug chương trình với gdb lệnh print system
Address of system
saved ebp
buf
Stack
frame
của
main
Return addr of system
Addr of “/bin/bash”
Địa chỉ chuỗi “/bin/bash”?
Thường biến môi trường SHELL=/bin/bash
gdb: x/s *((char **)environ+i)
i thứ tự của biến cần đọc trong danh sách các biến môi trường
Tự chèn thêm biến môi trường với lệnh export
Đọc tương tự với gdb
University of Information Technology (UIT), VNU-HCM
Return-to-lib-c: Gọi nhiều hàm?
19
Để thực thi chức năng phức tạp, thể cần gọi nhiều hàm libc
Cần “tạo” stack frame cho mỗi hàm được gọi sử dụng return
addr để nối thành chuỗi gọi hàm
Giả sử muốn lần lượt thực thi các hàm f1, f2, f3
Địa chỉ của stack frame giả: f1 < f2 < f3.
Return addr của f1 địa chỉ của f2, return addr của f2 địa chỉ
của f3 để thực thi luồng f1 f2 f3.
Lưu ý: cần gán return addr để bỏ qua phần code set-up stack của
mỗi hàm muốn gọi để không ảnh hưởng đến stack frame giả.
Saved ebp của f1 cần trỏ về vị trí ebp trong stack frame giả của f2,
tương tự cho saved ebp của f2 trỏ về vị trí ebp trong stack frame giả
của f3.
Nội dung trong stack frame giả phụ thuộc vào hoạt động của hàm f1,
f2, f3.
University of Information Technology (UIT), VNU-HCM
Return-to-lib-c: Gọi nhiều hàm? (2)
20
Overwritten ret addr
overwritten ebp
buf
Local variables of f1
ebp of faked f2
f1:
<set-up stack code>
instruction x
...
leave
ret
Return addr for f1
f2:
<set-up stack code>
instruction y
...
leave
ret
Local variables of f2
ebp of faked f3
Return addr for f2
f3:
<set-up stack code>
instruction z
...
leave
ret
Local variables of f3
Fake saved ebp of f3
Return addr for f3
Parameters for f1
Parameters for f2
Parameters for f3
Stack
frame
giả cho
f1, f2
f3

Preview text:

Trường ĐH CNTT – ĐHQG TP. HCM
NT521 - Lập trình an toàn &
Khai thác lỗ hổng phần mềm Buổi 09
Off-by-one & Return-to-lib-c 2
University of Information Technology (UIT), VNU-HCM Nội dung • Tấn công Off-by-one
• Tấn công Return-to-lib-c 3
University of Information Technology (UIT), VNU-HCM Tổng quan
• Khai thác lỗ hổng tràn bộ đệm - buffer overflow:
• Trường hợp lý tưởng:
• Có khả năng kiểm soát return addr: không dùng stack
canary, có thể ghi đè đến vị trí return addr
• Có thể truyền shellcode vào stack và thực thi: -z execstack
• Các trường hợp ràng buộc hơn? • Off-by-one
Giới hạn kích thước buffer có thể bị ghi đè, không đủ để ghi đè return addrReturn-to-libc
Shellcode cần viết quá phức tạp hoặc quá dài, stack không
cho phép thực thi code
ROP (Return Oriented Programming)
Stack không cho phép thực thi 4
University of Information Technology (UIT), VNU-HCM Tấn công Off-by-one 5
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Vì sao?
• Tấn công tràn bộ đệm trên stack đôi khi không cho phép
ghi đè trực tiếp địa chỉ trả về. void bar(){ char buf[256]; int i;
for(i = 0; i <= 256; i++) buf[i] = getchar(); // other statements… } void foo(){ bar(); }
Có vấn đề gì với đoạn code trên?
Dùng <= thay vì <
có thể nhập kí tự thứ 257, nhưng chưa đủ để ghi đè được return addr
→ Cần tấn công kiểu gián tiếp 6
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Ví dụ
• Luồng thực thi foo() bar() Return addr of foo Higher addr
buf được thiết kế có độ dài 256 Saved ebp bytes – 256 ký tự. Local variables of
• Giả sử buf nằm liền kề vị trí lưu foo saved ebp. Return addr of bar
• Nếu có thêm 1 ký tự được ghi Saved ebp thêm trong stack?
• Saved ebp của bar sẽ thay đổi
• Nếu saved ebp của bar thay đổi? buf
• Khi thực thi xong bar, foo sẽ không
tìm được đúng stack frame của mình Lower
→ foo không tìm được biến cục bộ và addr return addr Other local variables of bar 7
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Ví dụ (2)
• Nếu byte thấp nhất trong saved Higher
ebp của bar thay đổi thành giá trị Return addr of foo addr
nhỏ hơn, ví dụ 0x00? Saved ebp
• Saved ebp sẽ trỏ đến 1 vị trí Local variables of
nào đó thấp hơn stack frame foo gốc của foo Return addr of bar ?? Saved ebp xx 1 địa chỉ thấp hơn stack frame của foo buf Lower addr Other local variables of bar 8
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Ví dụ (3) • Ý tưởng: Higher
• Ghi 1 stack frame giả vào bộ nhớ Return addr of foo addr
đệm để giả mạo stack frame của Saved ebp foo.
• Điều khiển được các biến cục bộ Local variables of
của foo xem như cơ bản điều foo khiển được foo. Return addr of bar
• Ghi đè byte cuối của saved ebp Saved ebp xx
của bar để trỏ về stack frame giả. Return addr of foo Saved ebp buf Stack frame giả Local variables of cho foo foo Other local Lower variables of bar addr 9
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Ví dụ (4)
• Thậm chí tốt hơn nếu attacker có 1 return
addr có chủ đích bên cạnh stack frame Return addr of foo Higher giả. addr Saved ebp
• Có thể điều hướng sau khi thực thi xong foo. Local variables of
• Có thể khai thác như thế nào? foo • Inject code Return addr of bar
• Gán return address trong stack frame giả
của foo thành địa chỉ đoạn code muốn Saved ebp xx thực thi. Return addr of foo Saved ebp buf Stack frame giả Local variables of cho foo foo Injected code Lower addr Other local variables of bar 10
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Ví dụ (5)
• Kết luận về ví dụ:
• Lỗi lập trình trong việc xác định giới hạn
• Dùng <= thay cho < → gán giá trị cho ô nhớ nằm ngoài mảng
• Nếu buffer nằm gần saved ebp, tấn công Off-by-one có
thể cho phép ghi đè saved ebp.
• Kẻ tấn công sau đó có thể thay đổi saved ebp để trỏ đến 1 stack frame giả.
• Với stack frame giả, kẻ tấn công có thể kiểm soát return
addr, từ đó kiểm soát luồng thực thi. 11
University of Information Technology (UIT), VNU-HCM
Tấn công Off-by-one: Tổng kết
• Một số trường hợp truy xuất con trỏ không chính xác có thể
cho phép ghi đè trực tiếp hoặc gián tiếp các cấu trúc/dữ liệu
quan trọng, bao gồm return addr.
• Các dạng tấn công vào các lỗ hổng này rất khó ngăn chặn.
Một ví dụ khác có thể bị tấn công off-by-one:
void receive(int socket) { char buf[MAX];
int nbytes = recv(socket, buf, sizeof(buf), 0); buf[nbytes] = '\0’; ... } 12
University of Information Technology (UIT), VNU-HCM Tấn công Return-to-libc 13
University of Information Technology (UIT), VNU-HCM
Tấn công Return-to-lib-c: Vì sao?
• Tên gọi khác: Tấn công Arc-injection
• Ngữ cảnh: việc truyền code thực thi (shellcode) đôi khi khó
khăn trong khai thác lỗ hổng buffer overflow.
• Shellcode quá dài không để được trong buffer.
• Shellcode quá phức tạp
• Trên stack không cho phép thực thi code
→ Tận dụng code có sẵn trong chương trình, hay cụ thể là trong các thư viện C (libc)
Libc cung cấp các macro, các định nghĩa kiểu dữ liệu và các hàm cho các tác vụ
phổ biến như: xử lý chuỗi, tính toán toán học, xử lý input/output, cấp phát bộ nhớ,…
Ví dụ: printf(), scanf(), system(),…

• Mục tiêu: Ghi đè return address để điều hướng luồng chương
trinh đến các đoạn code có sẵn trong bộ nhớ. 14
University of Information Technology (UIT), VNU-HCM
Tấn công Return-to-lib-c: Ví dụ
• Cho đoạn chương trình ví dụ:
int main(int argc, char *argv[]){ char buf[4]; strcpy(buf, argv[1]); return 0; }
Có vấn đề gì với đoạn code trên?
Dùng strcpy là 1 hàm sao chép chuỗi nhưng không có cơ chế kiểm tra sự phù
hợp độ dài giữa nguồn (argv[1]) và đích (buf).

Mục tiêu: Khai thác lỗ hổng buffer overflow để mở shell tương tác
không truyền code thực thi.
• Giả sử biên dịch với option -z noexestack để ngăn thực thi trên code 15
University of Information Technology (UIT), VNU-HCM
Tấn công Return-to-lib-c: Ví dụ (2)
• Cho đoạn chương trình ví dụ:
int main(int argc, char *argv[]){ char buf[4]; strcpy(buf, argv[1]); return 0; } Ý tưởng
• Có thể mở shell bằng cách gọi hàm system(“/bin/bash”). • system() là 1 hàm libc.
• Tham số của hàm là command muốn thực thi Như thế nào?
• Đổi return address thành địa chỉ của hàm system
• Gán tham số đầu tiên thanh địa chỉ chuỗi “/bin/bash” 16
University of Information Technology (UIT), VNU-HCM
Tấn công Return-to-lib-c: Ví dụ (2)
• Cho đoạn chương trình ví dụ:
int main(int argc, char *argv[]){ char buf[4]; strcpy(buf, argv[1]); return 0; }
Stack trước khai thác
Stack sau khai thác Addr of “/bin/bash” Tham số và Other data in stack stack frame giả Return addr of system cho system Return addr of main Address of system ?? saved ebp saved ebp Stack Stack frame frame của buf của buf main main 17
University of Information Technology (UIT), VNU-HCM
Tấn công Return-to-lib-c: Ví dụ (3)
• Địa chỉ của hàm system?
• Debug chương trình với gdb và gõ lệnh print system
• Địa chỉ chuỗi “/bin/bash”?
• Thường có biến môi trường SHELL=/bin/bash
• gdb: x/s *((char **)environ+i)
i là thứ tự của biến cần đọc trong danh sách các biến môi trường
• Tự chèn thêm biến môi trường với lệnh export
• Đọc tương tự với gdb Addr of “/bin/bash” Return addr of system Address of system saved ebp Stack frame của buf main 18
University of Information Technology (UIT), VNU-HCM
Return-to-lib-c: Gọi nhiều hàm?
• Để thực thi chức năng phức tạp, có thể cần gọi nhiều hàm libc
→ Cần “tạo” stack frame cho mỗi hàm được gọi và sử dụng return
addr để nối thành chuỗi gọi hàm
• Giả sử muốn lần lượt thực thi các hàm f1, f2, f3
• Địa chỉ của stack frame giả: f1 < f2 < f3.
Return addr của f1 là địa chỉ của f2, return addr của f2 là địa chỉ
của f3 → để thực thi luồng f1 → f2 → f3.
• Lưu ý: cần gán return addr để bỏ qua phần code set-up stack của
mỗi hàm muốn gọi → để không ảnh hưởng đến stack frame giả.
Saved ebp của f1 cần trỏ về vị trí ebp trong stack frame giả của f2,
tương tự cho saved ebp của f2 trỏ về vị trí ebp trong stack frame giả của f3.
• Nội dung trong stack frame giả phụ thuộc vào hoạt động của hàm f1, f2, f3. 19
University of Information Technology (UIT), VNU-HCM
Return-to-lib-c: Gọi nhiều hàm? (2) Parameters for f3 f3: Return addr for f3 instruction z Fake saved ebp of f3 ... leave Local variables of f3 ret Parameters for f2 f2: Stack Return addr for f2 frame ebp of faked f3 instruction y giả cho ... f1, f2 và Local variables of f2 leave f3 ret Parameters for f1 Return addr for f1 f1: ebp of faked f2 instruction x Local variables of f1 ... leave Overwritten ret addr ret overwritten ebp buf 20
University of Information Technology (UIT), VNU-HCM