Ghi tập tin văn bản python stack tràn

Khai thác tràn bộ đệm dựa trên ngăn xếp có thể là hình thức khai thác phổ biến nhất và thông minh nhất để tiếp quản từ xa việc thực thi mã của một quy trình. Những khai thác này cực kỳ phổ biến cách đây 20 năm, nhưng kể từ đó, rất nhiều nỗ lực đã được thực hiện để giảm thiểu các cuộc tấn công tràn ngăn xếp của các nhà phát triển hệ điều hành, nhà phát triển ứng dụng và nhà sản xuất phần cứng, với những thay đổi thậm chí được thực hiện đối với các thư viện tiêu chuẩn mà các nhà phát triển sử dụng. Dưới đây, chúng ta sẽ khám phá cách thức hoạt động của tràn dựa trên ngăn xếp và nêu chi tiết các chiến lược giảm thiểu được đưa ra để cố gắng ngăn chặn chúng

Tìm hiểu sâu về các cuộc tấn công tràn bộ đệm dựa trên ngăn xếp

Hiểu các cuộc tấn công tràn dựa trên ngăn xếp bao gồm ít nhất một sự hiểu biết cơ bản về bộ nhớ máy tính. Bộ nhớ trong máy tính chỉ đơn giản là nơi lưu trữ dữ liệu và hướng dẫn—dữ liệu để lưu trữ số, chữ cái, hình ảnh và bất kỳ thứ gì khác và hướng dẫn cho máy tính biết phải làm gì với dữ liệu. Cả hai đều được lưu trữ trong cùng một bộ nhớ vì bộ nhớ rất đắt đỏ trong những ngày đầu của máy tính và việc dành riêng nó cho loại lưu trữ này hay loại lưu trữ khác là lãng phí. Cách tiếp cận mà dữ liệu và hướng dẫn được lưu trữ cùng nhau được gọi là kiến ​​trúc Von Neumann. Nó vẫn được sử dụng trong hầu hết các máy tính cho đến ngày nay, mặc dù như bạn sẽ thấy, nó không phải là không có sự phức tạp.

Về mặt sáng sủa, trong khi bảo mật không phải là yếu tố thúc đẩy trong thiết kế phần mềm và máy tính thời kỳ đầu, các kỹ sư đã nhận ra rằng việc thay đổi các hướng dẫn đang chạy trong bộ nhớ là một ý tưởng tồi, vì vậy, ngay từ những năm 90, các hệ điều hành và phần cứng tiêu chuẩn đã làm một . Thật không may, bạn không thực sự cần thay đổi hướng dẫn để thay đổi hành vi của chương trình đang chạy và với một chút kiến ​​thức, bộ nhớ dữ liệu có thể ghi cung cấp một số cơ hội và phương pháp để tác động đến việc thực hiện hướng dẫn

Lấy ví dụ đặc biệt này

#include 
#include 
#include 
int main[]{
	char realPassword[20];
	char givenPassword[20];

	strncpy[realPassword, "ddddddddddddddd", 20];
	gets[givenPassword];
	
	if [0 == strncmp[givenPassword, realPassword, 20]]{
		printf["SUCCESS!\n"];
	}else{
		printf["FAILURE!\n"];
	}
	raise[SIGINT];
	printf["givenPassword: %s\n", givenPassword];
	printf["realPassword: %s\n", realPassword];
	return 0;
}

Nếu bạn không biết ngôn ngữ lập trình C, không sao cả. Điều thú vị về chương trình này là nó tạo ra hai bộ đệm trong bộ nhớ có tên là

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
0 và
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
1 dưới dạng các biến cục bộ. Mỗi bộ đệm có khoảng trống cho 20 ký tự. Khi chúng tôi chạy chương trình, không gian cho các biến cục bộ này được tạo trong bộ nhớ và được lưu trữ cụ thể trên ngăn xếp cùng với tất cả các biến cục bộ khác [và một số nội dung khác]. Ngăn xếp là một không gian bộ nhớ tuần tự, rất có cấu trúc, vì vậy khoảng cách tương đối giữa hai biến cục bộ bất kỳ trong bộ nhớ được đảm bảo là tương đối nhỏ. Sau khi chương trình này tạo các biến, nó sẽ điền giá trị
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
0 bằng một chuỗi, sau đó nhắc người dùng nhập mật khẩu và sao chép mật khẩu được cung cấp vào giá trị
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
1. Khi nó có cả hai mật khẩu, nó sẽ so sánh chúng. Nếu chúng khớp nhau, nó sẽ in ra “
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
4. ” Nếu không, nó in ra “______15. ”

Đây là một ví dụ chạy

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd

Điều này chính xác như chúng ta mong đợi. Mật khẩu chúng tôi đã nhập không khớp với mật khẩu dự kiến. Có một cái bẫy ở đây. Lập trình viên [tôi] đã mắc một số lỗi thực sự nghiêm trọng, chúng ta sẽ nói về điều này sau. Tuy nhiên, trước khi chúng tôi đề cập đến điều đó, hãy mở trình gỡ lỗi và xem nhanh bộ nhớ để xem ngăn xếp trông như thế nào trong bộ nhớ khi chương trình đang thực thi

________số 8

Lúc này chương trình đã lấy dữ liệu vào và so sánh nhưng mình đã thêm vào đoạn code một đoạn ngắt để dừng nó trước khi thoát ra để chúng ta “nhìn” vào ngăn xếp. Trình gỡ lỗi cho chúng tôi biết chương trình đang làm gì và bộ nhớ trông như thế nào trên cơ sở đang chạy. Trong trường hợp này, chúng tôi đang sử dụng Trình gỡ lỗi GNU [GDB]. Lệnh GDB 'khung thông tin' cho phép chúng tôi tìm vị trí trong bộ nhớ của các biến cục bộ sẽ nằm trên ngăn xếp

[gdb] info frame
Stack level 0, frame at 0x7fffffffdde0:
 rip = 0x7ffff7a42428 in __GI_raise [../sysdeps/unix/sysv/linux/raise.c:54]; saved rip = 0x400701
 called by frame at 0x7fffffffde30
 source language c.
 Arglist at 0x7fffffffddd0, args: sig=2
 Locals at 0x7fffffffddd0, Previous frame's sp is 0x7fffffffdde0
 Saved registers:
  rip at 0x7fffffffddd8
[gdb] 

Bây giờ chúng ta đã biết vị trí của các biến cục bộ, chúng ta có thể in vùng bộ nhớ đó

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
0

Như đã đề cập, ngăn xếp là dữ liệu được lưu trữ tuần tự. Nếu bạn biết ASCII, thì bạn biết chữ 'a' được biểu thị trong bộ nhớ bằng giá trị

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
6 và chữ 'd' là
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
7 Bạn có thể thấy ở trên rằng chúng nằm ngay cạnh nhau trong bộ nhớ. Bộ đệm
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
0 nằm ngay sau bộ đệm
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
1

Bây giờ, hãy nói về những sai lầm mà lập trình viên [tôi] đã mắc phải. Đầu tiên, các nhà phát triển không bao giờ nên sử dụng hàm

msfuser@ubuntu:~$ gdb example.elf
.
.
.
[gdb] run
Starting program: /home/msfuser/example.elf 
aaaaaaaaaaaaaaaa
FAILURE!

Program received signal SIGINT, Interrupt.
0x00007ffff7a42428 in __GI_raise [sig=2] at ../sysdeps/unix/sysv/linux/raise.c:54
54	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
[gdb]
0 vì nó không kiểm tra để đảm bảo rằng kích thước của dữ liệu mà nó đọc khớp với kích thước của vị trí bộ nhớ mà nó sử dụng để lưu dữ liệu. Nó chỉ đọc văn bản một cách mù quáng và đưa nó vào bộ nhớ. Có nhiều hàm thực hiện chính xác cùng một việc—những hàm này được gọi là hàm không giới hạn vì nhà phát triển không thể dự đoán khi nào chúng sẽ ngừng đọc hoặc ghi vào bộ nhớ. Microsoft thậm chí còn có một trang web ghi lại cái mà họ gọi là các chức năng “bị cấm”, bao gồm các chức năng không giới hạn này. Mọi nhà phát triển nên biết các chức năng này và tránh chúng, đồng thời mọi dự án sẽ tự động kiểm tra mã nguồn cho chúng. Tất cả các chức năng này đều có từ thời kỳ mà bảo mật không bắt buộc như ngày nay. Các chức năng này phải tiếp tục được hỗ trợ vì hỗ trợ kéo sẽ phá vỡ nhiều chương trình cũ, nhưng chúng không nên được sử dụng trong bất kỳ chương trình mới nào và nên bị xóa trong quá trình bảo trì các chương trình cũ

Nhìn vào bản hack

Chúng tôi đã xem xét ngăn xếp, nhận thấy rằng các bộ đệm được đặt liên tiếp trong bộ nhớ và nói về lý do tại sao

msfuser@ubuntu:~$ gdb example.elf
.
.
.
[gdb] run
Starting program: /home/msfuser/example.elf 
aaaaaaaaaaaaaaaa
FAILURE!

Program received signal SIGINT, Interrupt.
0x00007ffff7a42428 in __GI_raise [sig=2] at ../sysdeps/unix/sysv/linux/raise.c:54
54	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
[gdb]
0 là một chức năng tồi. Bây giờ chúng ta hãy lạm dụng
msfuser@ubuntu:~$ gdb example.elf
.
.
.
[gdb] run
Starting program: /home/msfuser/example.elf 
aaaaaaaaaaaaaaaa
FAILURE!

Program received signal SIGINT, Interrupt.
0x00007ffff7a42428 in __GI_raise [sig=2] at ../sysdeps/unix/sysv/linux/raise.c:54
54	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
[gdb]
0 và xem liệu chúng ta có thể hack chương trình hành tinh hay không. Vì chúng tôi biết
msfuser@ubuntu:~$ gdb example.elf
.
.
.
[gdb] run
Starting program: /home/msfuser/example.elf 
aaaaaaaaaaaaaaaa
FAILURE!

Program received signal SIGINT, Interrupt.
0x00007ffff7a42428 in __GI_raise [sig=2] at ../sysdeps/unix/sysv/linux/raise.c:54
54	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
[gdb]
0 có vấn đề với việc đọc nhiều hơn mức cần thiết, nên điều đầu tiên cần thử là cung cấp cho nó nhiều dữ liệu hơn mức mà bộ đệm có thể chứa. Bộ đệm có 20 ký tự, vì vậy hãy bắt đầu với 30 ký tự

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
9

Chúng ta có thể thấy rõ rằng có 30 trường hợp của 'a' trong bộ nhớ, mặc dù chúng ta chỉ xác định không gian cho 20 ký tự. Chúng tôi đã tràn bộ đệm, nhưng không đủ để làm bất cứ điều gì. Hãy tiếp tục cố gắng và thử 40 trường hợp 'a. ’

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
0

Điều đầu tiên cần lưu ý là chúng tôi đã đi đủ xa để vượt qua không gian được phân bổ cho

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
1 và xoay sở để thay đổi giá trị của
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
0, đây là một thành công lớn. Tuy nhiên, chúng tôi đã không thay đổi nó đủ để đánh lừa chương trình. Vì chúng tôi đang so sánh 20 ký tự và chúng tôi đã viết tám ký tự vào bộ đệm
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
0, chúng tôi cần viết thêm 12 ký tự. Vì vậy, hãy thử lại, nhưng với 52 trường hợp của 'a' lần này

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
4

Thành công. Chúng tôi đã làm tràn bộ đệm cho

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
1 và dữ liệu được chuyển thẳng vào
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
0 để chúng tôi có thể thay đổi bộ đệm
msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
0 thành bất kỳ thứ gì chúng tôi muốn trước khi quá trình kiểm tra diễn ra. Đây là một ví dụ về tấn công tràn bộ đệm [hoặc ngăn xếp]. Trong trường hợp này, chúng tôi đã sử dụng nó để thay đổi các biến trong một chương trình, nhưng nó cũng có thể được sử dụng để thay đổi siêu dữ liệu được sử dụng để theo dõi quá trình thực thi chương trình

Thay đổi siêu dữ liệu



Sử dụng các cuộc tấn công tràn ngăn xếp chống lại siêu dữ liệu chương trình để ảnh hưởng đến việc thực thi mã không khác nhiều so với ví dụ trên. Chìa khóa là hiểu khái niệm về giá trị trả về. Cũng như chúng ta, máy tính làm nhiều việc cùng một lúc và sẽ ngừng làm việc này để làm việc khác trước khi quay lại nhiệm vụ ban đầu. Khi máy tính thực hiện các lệnh nằm ở một nơi khác trong bộ nhớ lệnh, nó sẽ lưu một ghi chú về vị trí của nó trước khi bắt đầu thực hiện để nó biết nơi quay lại khi hoàn thành tác vụ mới. Ghi chú đó—được gọi là địa chỉ trả về—chỉ đơn giản là địa chỉ trong bộ nhớ hướng dẫn nơi nó quay lại và bắt đầu thực hiện các hướng dẫn

Máy tính tuyệt vời và nếu bạn có thể thay đổi giá trị của địa chỉ trả lại, bạn có thể gửi nó đến bất cứ đâu bạn muốn. Những kẻ khai thác thường sẽ viết các hướng dẫn trong cùng một bộ đệm mà chúng làm tràn và sau đó trỏ thực thi trở lại chính bộ đệm, điều này cho phép kẻ tấn công trao mã chương trình và sau đó buộc nó thực thi mã đó

Một lưu ý là không có ví dụ nào trong số này sẽ hoạt động trên các hệ điều hành hiện đại từ xa nữa. Các nhà phát triển hệ điều hành, nhà phát triển ứng dụng, kỹ sư phần cứng và thậm chí cả trình biên dịch đều đã phản ứng và khiến việc thực hiện các cuộc tấn công tràn ngăn xếp trở nên khó khăn hơn nhiều

Điều gì đang được thực hiện để giảm thiểu những khai thác này?

Đã gần 20 năm kể từ thời kỳ hoàng kim của các cuộc tấn công tràn ngăn xếp và có rất nhiều biện pháp bảo vệ ngăn chặn chúng hoạt động tốt như bây giờ như trước đây. Một số biện pháp bảo vệ này bao gồm canary ngăn xếp, Ngẫu nhiên bố cục không gian địa chỉ [ASLR], cảnh báo trình biên dịch và thay đổi phần cứng để ngăn chặn việc thực thi mã trên ngăn xếp. [Ghi chú bên lề. Đối với một cuộc thảo luận lịch sử về ASLR trên Windows, hãy xem chủ đề Twitter xuất sắc nhất này của John Lambert. ]

Đầu tiên và quan trọng nhất, biện pháp bảo vệ tốt nhất chống lại các cuộc tấn công tràn bộ nhớ dựa trên ngăn xếp là sử dụng các phương pháp mã hóa an toàn—chủ yếu thông qua việc ngừng sử dụng các chức năng cho phép truy cập bộ nhớ không giới hạn và tính toán cẩn thận quyền truy cập bộ nhớ để ngăn kẻ tấn công sửa đổi các giá trị liền kề trong bộ nhớ. Rất đơn giản, nếu kẻ tấn công chỉ có thể truy cập vào bộ nhớ của biến mà chúng định thay đổi, thì chúng không thể tác động đến việc thực thi mã ngoài mong đợi của nhà phát triển và kiến ​​trúc sư

Thật không may, có hàng ngàn chương trình đã triển khai các chức năng không an toàn, không giới hạn để truy cập bộ nhớ và việc mã hóa lại tất cả chúng để đáp ứng các thực tiễn mã hóa an toàn đơn giản là không khả thi. Đối với các chương trình kế thừa đó, các nhà sản xuất hệ điều hành đã triển khai một số biện pháp giảm thiểu để ngăn chặn các hoạt động mã hóa kém dẫn đến việc thực thi mã tùy ý. Chúng ta có thể thấy điều này thực tế phần nào trong ví dụ của mình bằng cách chuyển đổi các biện pháp bảo vệ và đẩy xa hơn trong phần tràn của chúng ta

Một thay đổi nhanh chóng mà các trình biên dịch thực hiện ngay sau các cuộc tấn công dựa trên ngăn xếp là bắt đầu bao gồm các biện pháp bảo vệ đối với các phần dữ liệu quan trọng, chẳng hạn như địa chỉ trả về. Vì hầu hết các cuộc tấn công tràn ngăn xếp liên quan đến việc làm tràn một vị trí dữ liệu và ghi vào một vị trí dữ liệu khác, trình biên dịch đã đặt một giá trị hy sinh đã biết giữa bộ đệm và dữ liệu quan trọng, sau đó chương trình sẽ kiểm tra xem liệu giá trị hy sinh có bị thay đổi hay không trước khi sử dụng dữ liệu quan trọng. Nếu giá trị đó bị thay đổi thì rất có thể dữ liệu quan trọng cũng bị thay đổi nên việc thực thi sẽ dừng lại ngay lập tức. Vì sự thay đổi trong các giá trị hy sinh này có thể được xác định trước khi quá trình thực thi mã độc bắt đầu, nên các giá trị này được gọi là “chim hoàng yến. ” Nếu chim hoàng yến bị quấy rầy, mã ngoại lệ được thực thi và chương trình kết thúc

Giờ đây, bản thân những con chim hoàng yến xếp chồng lên nhau không chống được đạn, vì có một số cách để vượt qua chúng. Một phương pháp là tìm giá trị canary thông qua đọc bộ nhớ không giới hạn hoặc đoán. Trong một số trường hợp, giá trị hoàng yến là tĩnh và có thể dự đoán được. Khi kẻ tấn công biết giá trị canary, chúng có thể thay thế nó trong phần ghi đè. Vì lý do này, canaries thường chứa các ký tự khó gửi, chẳng hạn như “enter” [\x0a] hoặc “vertical tab” [\x0b]. “enter” Mặc dù là một thách thức đối với kẻ tấn công, nhưng điều này làm giảm entropy của giá trị canary và khiến chúng dễ tìm thấy hơn trong bộ nhớ

Để bỏ qua các biện pháp bảo vệ ngăn xếp canary bằng Bộ sưu tập trình biên dịch GNU [GCC], upi phải chỉ định rằng bạn muốn tắt các biện pháp bảo vệ, với cờ ‘‘-fno-stack-protection. ’

Để chứng minh, hãy biên dịch chương trình mà không cần bảo vệ và chuyển cho nó một bộ đệm lớn. Trong trường hợp này, tôi đang sử dụng một tập lệnh perl nội tuyến nhỏ để tạo một chuỗi 90 phiên bản 'a' và chuyển tập lệnh đó vào ví dụ chương trình. yêu tinh

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
8

Điều này dẫn đến sự cố chương trình, xảy ra khi cấu trúc bộ nhớ bị hỏng với dữ liệu xấu. Đây có thể là kết quả của việc ghi đè giá trị trả về và sau đó bộ xử lý gặp sự cố khi cố gắng truy cập bộ nhớ mới. Nếu chúng tôi đã ghi đè vị trí bằng một nơi nào đó mà CPU có thể truy cập, thì thật tuyệt khi làm như vậy

Bây giờ, hãy làm lại thử nghiệm, nhưng không tắt tính năng bảo vệ ngăn xếp gcc

msfuser@ubuntu:~$ ./example.elf 
test
FAILURE!
givenPassword: test
realPassword: ddddddddddddddd
9

Các thay đổi đối với phần cứng và hệ điều hành mất nhiều thời gian hơn nhưng chúng đã xảy ra. Một trong những biện pháp giảm thiểu đầu tiên được giới thiệu bởi các nhà cung cấp phần cứng và hệ điều hành là NX, hoặc bit không thực thi. Trên Windows, điều này được gọi là Ngăn chặn thực thi dữ liệu [DEP]. Nó cho phép các hệ điều hành xác định một số vùng bộ nhớ là không thể thực thi được và khi được gắn cờ như vậy, CPU sẽ không thực thi bộ nhớ đó. Về lý thuyết, không bao giờ có mã thực thi trên ngăn xếp, vì nó được thiết kế chỉ để lưu trữ giá trị dữ liệu. Dựa trên sự hiểu biết đó, các hệ điều hành đã phân loại ngăn xếp là không thể thực thi được, ngăn không cho mã tùy ý được đặt vào ngăn xếp và được thực thi

Ngoài việc bỏ qua để giảm thiểu sự giảm thiểu này, rõ ràng là mặc dù là một thông lệ kém, nhiều chương trình hợp pháp đã đặt các hướng dẫn trên ngăn xếp và thực thi chúng, và NX đã phá vỡ tất cả chúng. Điều đó buộc các hệ điều hành phải cho phép một số chương trình chọn không tham gia bảo vệ và những chương trình đó đã được tin tặc biết đến và tiếp tục là mục tiêu. Ngoài những chương trình đã chọn không tham gia, cách bỏ qua phổ biến nhất đối với NX là thông qua việc sử dụng lập trình hướng về [ROP], sử dụng mã có sẵn trong bộ nhớ hướng dẫn để thực hiện các tác vụ mong muốn. Hầu hết các chương trình sử dụng các bộ mã chung để thực hiện các tác vụ và ROP tận dụng mã chung này để thực hiện một tác vụ mong muốn. Đôi khi, những kẻ tấn công thiết lập việc thực thi một số đoạn mã trên nhiều thư viện trong một quy trình được gọi là chuỗi ROP. Vì mã mà kẻ tấn công cần đã có sẵn trong bộ nhớ hướng dẫn nên không cần phải đặt mã đó vào ngăn xếp để thực thi

Trong nỗ lực ngăn chặn các cuộc tấn công dựa trên ROP, các hệ điều hành bắt đầu ngẫu nhiên hóa vị trí của bộ nhớ hướng dẫn để ngăn kẻ tấn công biết mã mong muốn được lưu trữ ở đâu. Việc ngẫu nhiên hóa bộ nhớ hướng dẫn đó được gọi là ASLR, xáo trộn các khối bộ nhớ và làm cho vị trí của một đối tượng nhất định [bao gồm cả mã] trong bộ nhớ không còn là một giá trị cố định. Một cuộc tấn công hoạt động một lần có thể không hoạt động trở lại, vì mã mà kẻ tấn công cố thực thi có thể không còn ở đó, gây ra kết quả không thể đoán trước

Mặc dù hiệu quả, nhưng ASLR bị hạn chế bởi vì, giống như NX, không phải mọi phần bộ nhớ hướng dẫn đều phản ứng tốt với việc di chuyển, do đó, một số mã phải chọn không tham gia bảo vệ. Ngay cả đối với mã có thể xử lý ASLR, vẫn có những đường vòng. Bỏ qua phổ biến nhất tận dụng giới hạn mà bộ nhớ chỉ có thể được sắp xếp ngẫu nhiên theo khối. Nếu có cách xác định vị trí của một khối bộ nhớ, kẻ tấn công có thể tính toán vị trí của bộ nhớ mong muốn từ giá trị bị rò rỉ. Thật không may, vì ASLR không phải là thứ được đưa vào hệ điều hành, nên đôi khi chúng lưu trữ vị trí ngẫu nhiên của một thứ quan trọng ở một nơi đã biết, không giống như một nhân viên chọn một mật khẩu tốt nhưng lại ghi nó vào một ghi chú Post-It dưới bàn phím của họ. Một "gian lận" như vậy của hệ điều hành cho phép kẻ tấn công xác định vị trí của một đối tượng đã biết trong bộ nhớ, sau đó dựa trên vị trí của nó, chúng có thể tính toán vị trí của mã hoặc đối tượng mong muốn. Một lần nữa, giống như NX, ASLR không ngăn chặn hoàn toàn một cuộc tấn công, nhưng nó làm cho các cuộc tấn công trở nên khó khăn hơn và ít thành công hơn.

Tóm lại là

Thật tuyệt khi nói rằng các cuộc tấn công tràn dựa trên ngăn xếp đã biến mất do có các chiến lược giảm thiểu, nhưng thực tế không phải vậy. Các cuộc tấn công dựa trên ngăn xếp có thể không phổ biến ngày nay, nhưng chúng vẫn tồn tại. Do quy mô lớn của các nhà cung cấp hệ điều hành, không có khả năng một cuộc tấn công dựa trên ngăn xếp tồn tại trong Windows hoặc Linux nữa, nhưng các nhóm nhỏ hơn ít chú ý đến bảo mật hơn vẫn phát hành mã dễ bị tấn công—và không phải lỗ hổng nào cũng có thể được giảm thiểu bởi hệ điều hành

Làm cách nào để ghi tệp văn bản trong tràn ngăn xếp Python?

Làm cách nào để viết danh sách vào tệp văn bản trong Python? .
Mở tệp ở chế độ ghi. Truyền đường dẫn tệp và chế độ truy cập w cho hàm open[]
Lặp lại danh sách bằng vòng lặp for. Sử dụng vòng lặp for để lặp lại từng mục từ danh sách
Viết mục hiện tại vào tập tin
Đóng tệp sau khi hoàn thành thao tác ghi

Làm cách nào để tạo tệp txt bằng Python?

#tạo tệp văn bản bằng chức năng lệnh "w" f = open["myfile. txt", "w"] #Lệnh "w" này cũng có thể được sử dụng để tạo một tệp mới nhưng không giống như lệnh "x" lệnh "w .

Làm cách nào để in văn bản bằng Python?

Hàm Python print[] . Thông báo có thể là một chuỗi, hoặc bất kỳ đối tượng nào khác, đối tượng sẽ được chuyển thành chuỗi trước khi ghi ra màn hình.

Chủ Đề