Lỗ hổng này có thể bị khai thác trong từng trường hợp cụ thể cho phép kẻ tấn công có thẻ vượt qua các lớp xác thực người dùng mật khẩu và từ đó có thể chiếm quyền điều khiển hệ thống Gr
Trang 1MỤC LỤC
Trang 2Lời nói đầu
Ra mắt năm 1991 nhưng đến bây giờ nền tảng Linux vẫn ưa chuộng nhờ sở hữu bảo mật
và sự ổn định cực cao Tuy nhiên, mới đây hai chuyên bảo mật của đại học Valencia ( Hector Marco & Ismarel Ripoll) đã phát hiện ra một bug (lỗ hổng) cực kì nghiêm trọng trên một vài bản phân phối Linux Theo đó, chỉ cần nhấn phím backspace 28 lần, bất cứ
ai cũng có thể bypass mọi hệ thống bảo vệ mật khẩu trong quá trình khởi động máy tính Linux Lỗi này được đánh mã CVE là: CVE-2015-8370
Cụ thể, lỗ hổng trên được phát hiện trên Grub2 (Grand Unified Bootloader) - bootloader được nạp vào hệ thống Linux khi máy tính khởi động Sau khi nhấn 28 lần phím
backspace trong ô Grub username, hệ thống sẽ tự khởi động chương trình "Grub rescue shell" - cho phép truy cập không cần ủy quyền vào máy tính Sau đó, kẻ xấu có thể đàng
hoàng truy cập toàn bộ dữ liệu, ăn cắp, phá hoại hoặc có thể cài đặt các mã độc hoặc rootkit để kiểm soát thiết bị này
Trang 3I, Miêu tả
Ngày 10/12/2015 hai chuyên gia bảo mật của Cybersercurity Group đã phát hiện
ra 1 lỗ hổng bảo mật trong Grub2 Các phiên bản từ 1.98(12/2009) đến 2.02(12/2015) đều bị ảnh hưởng Lỗ hổng này có thể bị khai thác trong từng trường hợp cụ thể cho phép kẻ tấn công có thẻ vượt qua các lớp xác thực người dùng ( mật khẩu) và từ đó có thể chiếm quyền điều khiển hệ thống
Grub2 là bộ nạp khởi động được sử dụng bởi hầu hết các hệ thống Linux bao gồm một số hệ thống nhúng Điều này dẫn đến một số lượng lớn thiết bị bị ảnh hưởng khi Grub yêu cầu nhập username thì ấn phím Backspace 28 lần , nếu xuất hiện rescue shell thì có nghĩa là Grub của bạn bị ảnh hưởng
II, Mức độ ảnh hưởng
Khi kẻ tấn công khai thác thành công lỗ hổng này sẽ mở ra được Grub rescue shell Grub rescue shell là một shell mạnh mẽ cho phép:
• Leo thang đặc quyền: kẻ tấn công vượt qua lớp xác thực người dùng mà không cần password hay username Kẻ tấn công có toàn quyền truy cập vào grub’s console
• Đánh cắp thông tin: kẻ tấn công có thể tải lên 1 nhân hệ điều hành riêng ( ví
dụ từ USB) và sau đó từ một môi trường thoải mái hơn có thể sao chép toàn
bộ dữ liễu hoặc cài 1 rootkit
• Từ chối dịch vụ: kẻ tấn công có thể phá hủy bất cứ dữ liệu gì trong grub, ngoài ra hacker có thể ghi đè dữ liệu lên đĩa gây ra 1 cuộc tấn công DoS
III, Tìm hiểu lỗ hổng
Các lỗi (bug) được tìm thấy trong mã của Grub từ phiên bản 1.98 (12/2009) Lỗ được giới thiệu là b391bdb2f2c5ccf29da66cecdbfb7566656a704d có ảnh hưởng đến hàm grub_password_get()
Lỗi tràn dưới số nguyên được tìm thấy trong 2 hàm grub_username_get() và grub_password_get() nằm trong grub-cỏe/normal/auth.c và lib/cryto.c Cả 2 hầm
Trang 4này đều giống nhau ngoại trừ việc hàm grub_username_get() gọi phương thức printf() Đây chính là điểm khai thác lỗi
static int
grub_username_get (char buf[], unsigned buf_size)
{
unsigned cur_len = 0;
int key;
while (1)
{
key = grub_getkey ();
if (key == '\n' || key == '\r')
break;
if (key == '\e')
{
cur_len = 0;
break;
}
if (key == '\b') // Does not checks underflows !!
{
cur_len ; // Integer underflow !!
Trang 5grub_printf ("\b");
continue;
}
if (!grub_isprint (key))
continue;
if (cur_len + 2 < buf_size)
{
buf[cur_len++] = key; // Off-by-two !!
grub_printf ("%c", key);
}
}
grub_memset( buf + cur_len, 0, buf_size - cur_len); // Out of bounds overwrite
grub_xputs ("\n");
grub_refresh ();
return (key != '\e');
}
Nguyên nhân chính gây ra lỗi là do việc giảm giá trị biến cur_len không kiểm soát phạm vi
IV, Điểm khai thác
Lỗi tràn dưới số nguyên có thể được khai thác để gây lỗi bộ nhớ ( Off-by-two và Out of bounds overwrite) Các lỗi cũ ghi đè lên 2 byte ngay dưới bộ đệm của biến username ( biến cục bộ gọi phương thức đăng nhập của hàm
Trang 6grub_auth_check_authentication()), nhưng vùng này không chứa bất kì thông tin
có thể xây dựng lên 1 cuộc tấn công
Out of bounds overwrite là lỗi cho phép ghi đè số 0 lên vùng đệm của biến username Điều này do grub_memset() thiết lập để ghi đè số 0 nên các byte k sử dụng của vùng đệm biên username Để làm điều đó, mã tính toán các địa chỉ của các byte không sử dụng đầu tiên và bao nhiêu byte phải bị xóa trắng trong bộ đệm Kết quả của những tính toán được thông qua như là đối số cho grub_memset ():
grub_memset (buf + cur_len, 0, buf_size - cur_len);
Lợi dụng lỗi này hacker có thể bấm phím Backspace để giảm biến cur_len, tạo 1 giá trị cao Giá trị này được sử dụng để tính toán các địa chỉ bắt đầu để xóa: địa chỉ đích = buf+cur_len
Tại thời điểm này, một lỗi tràn bộ thứ hai xảy ra vì việc bổ sung có giá trị lớn này với các cơ sở địa chỉ nơi cư trú của tên đệm không có thể được giữ trong một biến 32-bit Do đó, chúng ta cần phải quản lý việc giảm đầu tiên và tràn thứ hai này để tính toán các địa chỉ đích ở grub_memset () sẽ bắt đầu đặt số 0 cho bộ đệm:
cur_len ; // Integer underflow
grub_memset (buf + cur_len, 0, buf_size - cur_len); // Integer overflow
Ví dụ sau đây sẽ giúp để hiểu làm thế nào chúng ta có thể khai thác này Giả sử rằng các bộ đệm tên nằm trong 0x7f674 địa chỉ và hacker bấm phím backspace chỉ một lần (sản xuất một underflow để 0xFFFFFFFF) memset kết quả sẽ là:
grub_memset (0x7f673, 0, 1025);
Đối số đầu tiên là: (buf + cur_len) = (0x7f674 + 0xFFFFFFFF) = (0x7f674-1) = 0x7f673, đối số thứ hai: là giá trị liên tục sử dụng để ghi đè lên khu vực này, trong trường hợp này 0, và số thứ ba là số byte để ghi đè lên: (buf_size-cur_len) = (1024
- (- 1)) = 1025 Vì vậy, các bộ đệm toàn bộ tên người dùng (1024) cộng với các byte đầu tiên trong bộ đệm sẽ được thiết lập bằng 0
Trang 7Do đó, số lần ấn phim Backspace (không giới thiệu bất kỳ tên người dùng), là số lượng các byte bên dưới tên người dùng được set về 0
Bây giờ, chúng tôi có thể ghi đè lên một số tùy ý của byte dưới tên người dùng, chúng ta cần phải tìm ra một địa chỉ bộ nhớ thú vị mà chúng ta có thể ghi đè lên với số không Một cái nhìn nhanh vào stack frame hiện tại cho thấy rằng chúng tôi
đã có thể ghi đè lên địa chỉ trở lại của grub_memset function () Những hình ảnh sau đây phác thảo bố trí ngăn xếp bộ nhớ:
Như thể hiện trong hình trên, địa chỉ trở lại của grub_memset ()là ở khoảng cách 16-byte từ bộ đệm tên người dùng Nói cách khác, nếu chúng ta bấm phím Backspace 17 lần, chúng tôi sẽ ghi đè lên các byte cao của địa chỉ trở lại Vì vậy, thay gọi lại hàm tại 0x07eb53e8 chúng tôi sẽ chuyển đến 0x00eb53e8 Khi grub_memset () kết thúc, dòng điều khiển được chuyển đến địa chỉ 0x00eb53e8 gây ra một khởi động lại Điều tương tự cũng xảy ra nếu chúng ta bấm Backspace
18, 19 hoặc 20 lần, trong mọi trường hợp hệ thống khởi động lại
Tại thời điểm này, chúng ta có thể chuyển hướng các luồng điều khiển
Trang 8Có tiến trình sau khi jumping tới 0x0?
Tại địa chỉ 0x0 các IVT (Interrupt Vector Table) của bộ xử lý chứa một loạt các con trỏ trong các hình thức phân khúc: offset
Ở giai đoạn đầu của tiến trình khởi động, bộ xử lý và khuôn khổ thực hiện không đầy đủ các chức năng Tiếp theo là những khác biệt chính đối với môi trường thực thi của một quá trình thường xuyên với:
• Bộ xử lý là trong "chế độ bảo vệ" Grub2 cho phép chế độ này ở đầu
• Bộ nhớ ảo không được kích hoạt
• Không có bảo vệ bộ nhớ Các bộ nhớ có thể đọc / ghi / thực thi Đó là, không NX / DEP
• Bộ vi xử lý thực thi các tập lệnh 32-bit, thậm chí trong các kiến trúc 64-bit
• Bộ vi xử lí tự sửa "Nếu ghi ảnh hưởng đến một lệnh tìm nạp trước, hàng đợi prefetch không còn giá trị."
• Không stack Smashing Protector (SSP)
• Không Address Space Layout Randomization (ASLR)
Do đó, nhảy đến 0x0 không gây ra một cái bẫy của chính nó, nhưng chúng ta cần phải kiểm soát dòng chảy thực hiện để đạt được các mục tiêu chức năng grub_rescue_run () có chứa các vòng lặp chính của Rescue Shell grub2
Trang 9Chúng ta kiểm soát được gì khi nhảy đến 0x0?
Các chính "trong khi" vòng lặp của grub_username_get () kết thúc khi người dùng chạm hoặc [Enter] hoặc [Esc] chính Các register % ebx chứa giá trị của phím đánh máy cuối cùng (0xd hoặc 0x8, Nhập hoặc mã ascii Esc tương ứng) Các register
%esi giữ giá trị của biến cur_len
Các điểm con trỏ chỉ dẫn đến địa chỉ 0x0 Register % esi chứa giá trị -28 (khai thác công trình bằng cách nhấn 28 lần backspace), và sau đó nhấn [Enter] (% ebx == 0xb)
Kỹ thuật đảo ngược của IVT
Nếu trạng thái của bộ xử lý là một tóm tắt trong bảng trước đó, các mã tại IVT thực hiện một cái gì đó giống như một memcpy (), mà bản sao từ địa chỉ được trỏ bởi% esi để 0x0 (chính nó) Do đó, IVT là một mã tự sửa chữa, và chúng ta có thể chọn các khối mã mà chúng ta muốn sao chép từ
Trình tự sau đây cho thấy trình tự của mã thực sự thực hiện các register %esi có giá trị -28 (0xffffffe4)
Trang 10Trong lần lặp thứ ba, mã kết quả chứa một lệnh retw tại 0x0007 Các con trỏ có giá trị bằng% esp là 0xe00c Và như vậy, khi hướng dẫn retw được thực thi, lưu lượng thực thi nhảy vào 0xe00c Địa chỉ này thuộc về chức năng grub_rescue_run ():
<grub_rescue_run>:
0xdfef: push %ebp
0xdff0: mov %esp,%ebp
0xdff2: sub $0x24,%esp
0xdff5: push $0xe90a
0xdffa: call 0xd53b #
0xdfff: add $0x10,%esp
0xe002: call 0xbfd2 #
0xe007: xor %edx,%edx
0xe009: lea -0xc(%ebp),%eax
->0xe00c: movl $0x0,0x16ce0 >
0xe016: call 0xdf28
.
void attribute ((noreturn)) grub_rescue_run (void){
while (1) {
char *line;
/* Print an error, if any */
grub_print_error ();
->grub_errno = GRUB_ERR_NONE;
grub_rescue_read_line (&line, 0, NULL);
if (! line || line[0] == '\0') continue;
Trang 11grub_rescue_parse_line (line, grub_rescue_read_line,
NULL);
grub_free (line);
}
}
Trang 12May mắn thay, các nội dung của bộ nhớ đã bị thay đổi nhỏ, và nó có thể sử dụng tất cả các chức năng của GRUB Chỉ các vector ngắt đầu tiên của IVT đã được sửa đổi, và kể từ bộ vi xử lý hiện đang ở chế độ bảo vệ, các IVT không còn sử dụng Mặc dù chúng ta nghiên cứu hàm GRUB2 rescure , chúng ta không thực sự chứng thực Nếu chúng ta trở lại với chế độ "bình thường", đó là menu grub và với khả năng chỉnh sửa đầy đủ, GRUB sẽ yêu cầu người dùng và mật khẩu hợp lệ Vì vậy, chúng ta có thể trực tiếp bắt đầu gõ lệnh GRUB2, hoặc thậm chí bao gồm các module mới để thêm chức năng GRUB mới, để triển khai các phần mềm độc hại vào hệ thống hoặc khởi động một môi trường thoải mái hơn nhiều bằng cách chạy một shell bash hoàn chỉnh từ một Linux Để chạy bash trong Linux, chúng ta có thể
sử dụng các lệnh GRUB2 như linux, initrd hoặc insmod
Trang 13Mặc dù sử dụng GRUB2 lệnh để chạy một hạt nhân Linux để triển khai các phần mềm độc hại là hoàn toàn có thể, chúng tôi thấy rằng, một giải pháp đơn giản là để
vá mã của GRUB2 trong RAM để luôn được xác thực và sau đó trở về chế độ
"bình thường" Ý tưởng để làm điều đó, là để sửa đổi các điều kiện mà checkes cho
dù người sử dụng đã được chứng thực hay không Hàm này là is_authenticated () trong file grub-core / normal / auth.c
Sửa đổi này được thực hiện bằng cách sử dụng write_word trong GRUB2 rescure
Và sau đó, mọi thứ đã sẵn sàng để quay trở lại chế độ GRUB2 bình thường Nói cách khác, chúng ta có thể nhập vào trong "chế độ chỉnh sửa" và GRUB2 sẽ không yêu cầu người dùng hoặc mật khẩu
Trang 14grub rescue> write_word 0x7eb514e 0x90909090 grub rescue> normal
Trang 15V, Một cuộc tấn công ATP sửa dụng lỗi 0-day này như thế nào
Truy cập vật lý là một "cao cấp" tính năng do APTs (hoặc nội bộ) Một trong những mục tiêu chính của một APT là ăn cắp thông tin nhạy cảm hoặc Cyberspying Sau đây chỉ là một ví dụ rất đơn giản về cách một APT có thể lây nhiễm sang một hệ thống và có được sự kiên trì để phía sau ăn cắp dữ liệu của người dùng Sau đây tóm tắt các cấu hình hệ thống:
• BIOS / UEFI được bảo vệ bằng mật khẩu
• chế độ chỉnh sửa GRUB2 được bảo vệ bằng mật khẩu
• khởi động bên ngoài bị vô hiệu hóa: CD-ROM, DVD, USB, Netboot, PXE
• Các dữ liệu người dùng (HOME) được mã hoá
Trang 16Như đã chỉ trước, mục tiêu của chúng ta là để ăn cắp dữ liệu của người dùng
Kể từ khi dữ liệu được mã hoá, chiến lược, chúng tôi sẽ sử dụng là để lây nhiễm
hệ thống và chờ cho đến khi người dùng giải mã dữ liệu (bằng cách đăng nhập vào hệ thống) và sau đó truy cập vào các thông tin ở plain
Chuẩn bị môi trường để triển khai malware
Bằng cách vá GRUB2 như trước đây, chúng ta có thể dễ dàng chỉnh sửa các mục nhập linux để tải một hạt nhân Linux và có được một root shell Đây là một thủ thuật cũ nhưng vẫn còn sử dụng, chỉ bằng cách thêm init = / bin / bash
để mục linux, chúng ta sẽ có được một root Linux shell, đó là một môi trường thoải mái hơn nhiều cho việc triển khai phần mềm độc hại của chúng ta
Trang 17Lưu ý rằng kể / bin / bash là quá trình đầu tiên chạy, syslog daemon không chạy, và do đó, các bản ghi không được ghi lại Đó là, truy cập này sẽ không thể được phát hiện bằng cách sử dụng bình thường theo dõi Linux
Triển khai các malware và cài cắm lâu dài
Để khai thác 0-Day grub2 lỗ hổng này, chúng ta đã sử dụng một PoC đơn giản PoC Đây là một thư viện Firefox sửa đổi mà tạo ra một quá trình mới và chạy một trình bao ngược đến một máy chủ kiểm soát tại cổng 53 Rõ ràng, đây là một ví dụ đơn giản, và một phần mềm độc hại thực tế sẽ exfiltrate thông tin nhiều hơn lén lút
Trang 18Các thư viện sửa đổi đã được tải lên VirusTotal báo cáo 0 nhiễm / virus trong số
55 công cụ Firefox là một trình duyệt web có sử dụng Internet, và gửi yêu cầu tới HTTP và cổng DNS, do đó, nó không xuất hiện để nghi ngờ rằng chuyện phần mềm độc hại của chúng tôi với các cổng này
Để lây nhiễm hệ thống chúng ta chỉ đơn giản là đặt thư viện sửa đổi libplc4.so chúng tôi vào một USB và sau đó thay thế một bản gốc Chúng ta phải gắn với quyền ghi hệ thống và gắn USB như thể hiện trong hình ảnh sau đây:
Khi bất kỳ người sử dụng thực hiện các trình duyệt Firefox, một shell sẽ được gọi Tại thời điểm này tất cả các dữ liệu của người dùng được giải mã, cho phép chúng tôi để ăn cắp bất kỳ loại thông tin của người sử dụng
Để kết thúc phần duy trì, nó có giá trị đề cập đến đó bằng một sửa đổi hạt nhân đơn giản mà nằm trong phân vùng / boot, mà theo mặc định không được mã hoá, chúng ta có thể nâng cao đặc quyền để triển khai một phần mềm độc hại dai dẳng hơn
Trang 19VI, Vá lỗi
Chúng ta có thể cập nhật bản vá lỗi như sau
$ git clone git://git.savannah.gnu.org/grub.git grub.git
$ cd grub.git
$ wget http://hmarco.org/bugs/patches/0001-Fix-CVE-2015-8370-Grub2-user-pass-vulnerability.patch
$ git apply 0001-Fix-CVE-2015-8370-Grub2-user-pass-vulnerability.patch
Tài liệu tham khảo:
http://hmarco.org/bugs/CVE-2015-8370-Grub2-authentication-bypass.html https://www.youtube.com/watch?v=cr464P8Yv8Q