Những trận tấn công đầy hiểm họa - Cách phá vỡ Windows
Giới thiệu
Bài viết này minh hoạ một phát sinh tấn công mới đến Microsoft Windows, và có th đến các hệ
thống thông điệp khác (message-based systems). Những lỗi được minh ho trong bài viết này,
thời điểm bài này được viết, thuc dạng không thể chữa được. Giải pháp duy nhất để loại trừ
những loi tấn công này đòi hỏi chức năng không có sẵn trong hệ điều hành Windows, và ngay
cả trong những ứng hoạt khác cho hệ Windows. Lâu nay Microsoft biết rõ những lỗi này; khi tôi
cảnh báo họ loại tn công trên, họ cho biết rằng họ không xếp loại phương thức tấn công đó n
một dạng lỗi của Windows - bạn có thể xem bức điện thưđây -1-. Khảo cứu trên bùng ra từ lời
phát biểu của ông Jim Allchin, phó chủ tịch Microsoft, cho rằng có quá nhiều lỗi trong hệ
Windows đến nỗi, nếu mã nguồn của Windows bị tiết lộ sẽ trở nên mối đe doạ đến an ninh quốc
gia. Ông ta đề cập đến “xếp hàng tng điệp” (Message Queuing), và ngay sau đó hối hận vì đã
đề cập đến vấn đề này. Tuy nhiên, dựa trên số lượng kho sát trên toàn thế giới hiện nay đến
vấn đề trên sau lời pt biểu của ông Allchin, đây là lúc cng đồng “ trắng” -2- lột tả thực
trạng này.
Bài viết này thuộc dạng tng bước một chỉ dn cách khai thác một điển hình của lỗi ở trên.
nhiều phương pháp tấn công khác đã được bàn thảo, tuy nhiêndụ của các loại tấn công khác
không được trình bày ở đây. Có rất nhiều cách khai thác các lỗi trên và nhiều biến ti của từng
giai đoạn được trình y. Ðây chỉ là một ví dụ.
Nền tảng - hệ thống thông điệp của Win32
Các nội ứng trình của Windows hoàn toàn được điều hành xuyên qua phương pháp ứng dụng
thông điệp. Khi một phím được nhấn, một thông điệp được gởi đến khung động hiện tại (current
active window), thông điệp này cho biết một phím nào đó đã được “nhấn”. Khi Windows xác định
một ứng trình cn v li phạm vi của client, Windows gởi một thông điệp đến ứng trình này. Thật
ra, khi một biến cố (event) xảy ra và một ng trình nào đó cần biết, nó sẽ gởi đi một thông điệp.
Những thông điệp này được đặt vào một hàng đợi (queue) và được ứng trình tuần tự xử lý.
Ðây là một cơ chế hết sức đáng tin cậy để điều hành các ứng trình. Tuy nhiên,chế dùng để
điều hành các thông điệp trên Win32 bị lỗi. Bất cứ một ứng trình nào cũng có thể gởi thông điệp
đến bt c khung (window) nào trên cùng desktop, bất chấp ứng trình gi thông điệp có làm chủ
khung đó hay không, và bất chấp ứng trình được nhận thông điệp có muốn nhận các thông điệp
này hay không. Hoàn toàn không có một cơ chế nào dùng để xác minh nguồn gc của các thông
điệp; không có cách nào để phân biệt sự khác nhau giữa một thông điệp được gi từ một ứng
trình hiểm độc và một thông điệp từ lõi (kernel) của Windows. Ðó là thiếu sót cơ chế xác minh
mà chúng ta sẽ khai thác với ch đích: sử dụngc thông điệp này đ thao túng các khung và
các quy trình làm chủ các window trong Windows.
Tổng quát
Trong ví dụ này, tôi sẽ khai thác Network Associate VirusScan phiên bản 4.5.1, chạy trên
Windows 2000 Professional. Tôi truy nhập như “guest” và VirusScan Console chạy trên desktop là
“LocalSystem”, mục đích dùng để lừa VirusScan chạy mã riêng để gia tăng chủ quyền cho tôi.
Mục đíchy đạt được qua nhiều phân đoạn đơn giản:
1. Tìm một khung thích hợp trong VirusScan (một hòm chnh [edit box] là hoàn hảo), và lấy một
khung đó để xử dụng.
2. Bỏ đi giới hạn phân độ trong edit box để tôi có th đánh vào một số lượng dữ kin tùy ý.
3. Dán vào mt số mã nh phân (binary code).
4. Buộc VirusScan thi triển mã của tôi (như LocalSystem)
Những bước trên thực s rất dễ làm. Windows cung cấp trọn bộ các chức năng tiện dụng mà
chúng ta cần.i viết một ứng trình nhỏ gi là Shatter -3- nó thực hiện chức năng gia tăng chủ
quyền này. Bạn cũng sẽ cần một hex editor có khả năng chép dữ liệu nhị phân vào clipboard (tôi
dùng UltraEdit (www.ultraedit.com)), và một debugger (tôi dùng WinDbg
(www.microsoft.com/ddk/debugging/installx86.asp)).
XIN NHỚ: Vài bộ quét virus cảnh báo người dùng virusWin32/Beavuh” trong hồ sơ sploit.bin
thuộc phần nén Shatter.zip. Ðây không phivirus. Bộ quét đánh dấu đúng hồ sơ này
(sploit.bin) - mã nguồn của hồ sơ y đưc thiết kế dùng để mở một command shell và tra nó
vào một socket của mạng. Một cách tổng quát mà nói, làm như vậy không tốt (đối với bảo mt),
bởi thế bộ qt có phản ứng đúng trong quy trình tạo cảnh báo. Mã nguồn này quả thật được
thiết kế vi dụng ý đen tối, tuy nhiên bộ quét nhận diện nó như mt thứ virus sai.
Các thông điệp của Windows bao gồm 3 phần, một phần nhận diện cho thông điệp và hai tham
số. Các tham số được sử dụng một cách khác nhau tùy thuộc vào thông điệp gì được gởi. Ðiều
này tạo điều kiện đơn giản hơn cho chúng ta, vì cng ta chỉ phải lo đến 4 điểm: một điu dụng
khung (window handle) để nhận thông điệp, một thông điệp và hai tham số. Hãy thử xem
chuyện này dễ như thế nào..
Bước 1: Tìm khung
Chúng ta cần xác định một loại quản trị điều chnh (edit control) nào đó - một nơi chúng ta có
thể đánh dữ kiện vào. Ðừng ngại nếu b giới hạn, chúng ta có thể hoá gii vấn đề này. Khởi động
VirusScan console và đánh vào nút đầu tiên - “New Task”. Một cách thuận tiện, trên đầu của
dialog này hiện ra một edit box. i này tuyệt hảo. Bây giờ, chúng ta cần một điều dụng (handle)
để chúng ta có th tương tác (interact) với nó. Windows sẵn sàng cho chúng ta một handle đến
bất cứ một window nào chúng ta muốn - chúng ta chcần hỏi nó. Khởi động Shatter điều
chỉnh vị trí để bạn có thể thy được VirusScan edit control bên dưới. Bấm vào “Get cursor
window” - Shatter s thêm và một đơn vị trong hòm danhch bên dưi tương tự như “102f2 -
Get cursor window”. Cái này là do chúng ta yêu cấu Windows cho chúng ta một handle đến
window trực tiếp phía dưới cursor. Chuyển cursor sang VirusScan edit control và đánh phím
“Space” đ gọi Shatter một lần nữa. Shatter sẽ xoá hòm danh sách và cho bạn biết handle của
mục tiêu window - trường hợp của tôi là 30270. Bây gi chúng ta có thể tương c với mt
window đang chạy với tính cách lập trình và với chủ quyền cao hơn. Hãy dán vào một ít
shellcode -4-.
Bước 2: Xóa bỏ các hạn chế
Khi đã có một window handle, chúng ta có thể gởi bt cứ thông điệp gì theo ý muốn đến control
này và nó s thừa hành yêu cầu một cách mù loà. Cứ theo từng bước một, đầu tiên chúng ta
phải nắm chắc là có đ khoảng trống cho shellcode.
Trong Shatter, đánh window handle của bn vào hòm “Handle”. Thông điệp để chnh phân đ tối
đa của các ch trong một edit box là EM_SERLIMITTEXT. Tham số thứ nhất dành cho phân độ
tối đa của chữ, và khỏi cần quan tâm đến tham số thứ nhì. Ðánh s 4 vào box WPARAM, và 0 và
box thứ 3. Bấm vào EM_SETLIMITTEXT để gởi thông điệp và thử đánh gì đó vào trong edit box
của VirusScan. Bạn chắc hẳn không thể đánh hơn 4 chữ. Thay đổi số 4 thành FFFFFFFF và gởi
thông điệp lại. Bây giờ thử đánh vào edit box của VirusScan; bạn có khoảng trng hơn 4Gb (trên
lý thuyết) trong phần edit control. Nhất định phải đủ chỗ cho c một shellcode lãng phí nhất.
Bước 3: Tiêm shellcode
Kế tiếp, hãy thử dán cái gì đó vào trong box. Ðúng là bạn có thể dùng right-click và chọn Paste,
nhưng để tho mãn các tham số cứ nghĩ là chúng ta không thể làm như vậy được. Xoá edit box
của VirusScan và khi động Notepad. Ðánh vài chữ vào trong Notepad, rồi chép những chữ y.
Trở lại Shatter, chúng ta muốn gởi VirusScan một thông đip từ trong Clipboard (vừa chép
trên) đó là WM_PASTE. Cả hai tham số cho thông điệp này nên là zero, bởi thế phải chỉnh
WPARAM và LPARAM thành zero, để yên handle như vy. Bấm vào WM_PASTE và xem những
chữ của bạn xuất hin trên edit box của VirusScan. Bấm một lần nữa, hẳn phải có chữ của
bạn xuất hiện lần thứ hai. Vui nhỉ?
Nào, “quậy” vy là đủ. Xoá edit box của VirusScan một lần nữa và khởi động hex editor của bạn.
Tải sploit.bin trong hồ sơ nén Shatter. Shellcode này lấy từ Jill (Hey, Dark Spyrit!),nó khởi động
một command shell tầm xa trở ngược lại bạn. Nó được hard-coded để gởi command shell đến địa
chỉ loopback ti port 123, lúc này là lúc thích hợp để khởi động một Netcat listener -5- trước khi
bạn qn. Khởi động một cmd (32-bit command line), đánh vào “nc -lp 123” và khỏi lo đến nó
nữa. Trở li hex edit, chép shellcode vào clipboard, bạn nht thiết phải chép trọn bộ shellcode
(bao gồm luôn FOON từ đầu - chúng ta s cần đến nó trong vòng 1 giây). Trở li Shatter và bấm
nút WM_PASTE lần nữa. Bạn hẳn thấy hàng loạt chữ qi đản trong edit box của VirusScan, đó
là shellcode của chúng ta đã được dán vào thành công.
Bước 4: Thi hành mã
Ðây là phần duy nht của trọn bộ chu trình đòi hỏi kỹ năng. Khởi động debugger của bạn và đính
nó vào chu trình avconsol.exe (dùng lệnh WinDbg: s -a 00000001 10000000 “FOON”, bạn cũng
thể dùng một debugger khác. Viết xuống vị trí bộ nhớ (memory location) nơi dòng hiển thị vị
trí bộ nhớ xuất hin; có lẽ nó sxuất hin một vài lần, đừng hỏi tôi ti sao. Bt cứ dòng nào
cũng được. Trên system của tôi, shellcode xuất hiện ở 0x00148c28, giá trị này có lẽ không khác
mấy nếu bạn ng cùng một phiên bản.y giờ tắt bỏ debugger, truy cập vào như guest và
chuẩn bị đón nhận chủ quyền LocalSystem. Theo tng bước 1 đến 3 li, nhớ là mọi thứ vẫn làm
việc như guest. Ðừng quên Netcat listener để nhn shell.
Lúc này l bạn đang cho rằng thủ thuật đính vào mt debugger là một thứ hot đng mang
tính chủ quyền. Ðúng vậy. Tuy nhiên,ơng tự như khi viết khai thác phần tràn bộ đệm (buffer
overflow), bạn có th làm chuyện y trên bất cứ bộ phận nào của system; bạn chỉ cần ti địa chỉ,
địa chỉ này nhất định phải làm việc trên bất cứ system o cùng phiên bản. Thật ra bạn cũng
chẳng cn phải làm chuyện này. Hầu hết các ứng trình đều có điu dụng ngoại lệ (exception
handlers) (VirusScan nhất định phi có), bởi thế nếu các ứng trình có vi phạm acess violation,
chúng ch xử lý với violation này và tiếp tục hoạt động thay vì treo máy. Bởi thế, chẳng có gì
ngăn bạn dán vào vài trăm Kb NOPs rồi cứ lần dò qua bộ nhớ cho đến khi đụng đến đúng đa chỉ
shellcode của bạn sẽ đưc thi hành. Chưa hẳn là đẹp mt, nhưng chy được.
Thông điệp cuối chúng ta sắp sửa tận dụng là WM_TIMER. Phần này i bt thường và khá nguy
hiểm vì nó có thể chứa (đi loi như tham số thứ nhì) đa chỉ của chức năng hồi khuyển timer
(callback function). Nếu tham số thứ nhì không phải là zero, phần thi hành sẽ nhảy thẳng đến vị
trí đã định. Ðúng vậy, bạn không đọc sai; bạn có thể gởi một thông đip WM_TIMER ti bất cứ
window nào vi trị giá không phảizero cho tham số thứ nhì (tham số th nhất là timer ID) và
phần thi hành nhảy thẳng tới đa chỉ đó. Theo tôi biết, thông điệp chẳng đến xếp hàng trong dãy
thông điệp (message queue), bởi thế ứng trình này không có cơ hội để tránh thông điệp đó. Ngớ
ngẩn, ngớ ngẩn, ng ngẩn....
Vậy, bên trong Shatter, handle chc phải được chỉnh dụng edit control của VirusScan để chứa
shellcode của chúng ta. Tham s thứ nhất có thể bất cứ giá trị gì bạn muốn và tham số thứ hai
nên dùng 512 bytes hoặc hơn địa chỉ chúng ta đã chọn ra từ debugger ở trên (chúng ta1K
NOP trước shellcode, bởi vậy chúng ta hẳn rt ngay vào gia các địa chỉ); trên system của tôi đó
là: 0x148c28 + 0x200 = 0x148e28. Bấm vào WM_TIMER và netcat listener ca bạn s thức dậy
với một command prompt. Một lệnh WHOAMI sẽ cho thấy bạn quả thật chuyển hóa từ guest
sang LocalSystem -6-. Enjoy.
Các kỹ thuật khác
một số cách khácn nhng c chúng làm ở trên, sử dụng các cơ chế căn bản tương t
nhưng có lẽ hơn phức tạp hơn. Thông đip EM_GETLINE ra lệnh một edit control chép phần
chứa của nó tới một địa đim đnh sẵnn trong thông đip. Làm cách nào để bạn viết một số
lượng tùy thích dữ liệu vào các địa chỉ trong bộ nhớ theo ý muốn? Bạn muốn khai thác dễ dàng
như thế nào? Chúng ta đã thấy các giới hạn có thể được loi b từ phân độ của một edit control;
chuyện gì xy ra khi một ứng trình ph thuộc vào các giới hạn này? Khi một ứng tnh dự phỏng
16 bytes dữ liệu t mt edit box có giới hạn 16 bytes, chúng ta có th đánh vào mt vài gigs.
Mọi người, đếm đến ba: 1...2...3.... Tràn Bộ Ðm! Có lẽ trên stack nữa, bởi 16 bytes dữ liệu chắc
hẳn là không phải từ trữ liệu của bộ nhớ (heap). n nữa, khi chúng ta gởi WM_TIMER đi, tham
số chúng ta ấn định cho timer ID bị đẩy vào trong chồng memory (stack) cùng với cả đống rác
rưởi khác. Ðể tìm một chức năng có thể tận dụng được chức năng ca tham số thứ 3 vàng
của các tham số khác là điều không thể không mường tượng được, chức năng này cho phép
chúng ta nhảy thẳng vào khai thác chỉ bằng một thông điệp.
Nói về trữ liu của bộ nhớ, có thêm một điểm ác liệt cho các loi khai thác như trên. Tổng quát
mà nói, các ứng trình thường tạo c dialog box trên trữ liệu của bộ nhớ trước khi những chế
hoạt trong bộ nhớ xảy ra; bi vậy shellcode của chúng ta nằm ở dạng tĩnh (static). Kinh nghiệm
bản thân tôi thấy hiếm khi có hơn 20 bytes được chuyển dịch giữa các instances. Các địa chỉ tĩnh
có hoán chuyển cũng không thành vấn đề, nhưng, ai mà lo? Gởi mt ứng trình một thông điệp
EM_GETLINE để nó viết shellcode của bạn đến vị trí bạn muốn (thật là quỷ quái, viết chồng lên
trữ liệu của bộ nhớ. Ai mà lo?) và rồi chỉ định cùng địa ch trong thông điệp WV_TIMER. Một
cách khai thác hoàn toàn không có NOP! Thật là nhộn.
Sửa lỗi
Rồi, kiểu khai thác này khá dễ dàng. Vy mọi người làm sao sửa lỗi này? Tôi thấy có hai phương
pháp nhanh và ẹ sẽ phá vỡ hàng loạt chức năng khai thác và một giải pháp lê thê, gii pháp y
sẽ không bao giờ là một giải pháp trọn vẹn. Ðể tôi giải thích.
1. Không cho phép thiên hạ lược duyệt (enumerate) windows -7- Nguy hiểm. Ðổ v hàng loạt.
Trên mặt lý thuyết mà nói, có thể chận đng enumerate, tuy nhiên, bản thân tôi rất ghét khi
thấy thiên hạ cố công cố sức mà chẳng biết loi windows gì đang ở trên desktop khi họ cần.
2. Không cho phépc thông điệp chuyển dịch giữa các ứng trình với những chủ quyền khác
nhau. Ðiều này có nghĩa, bạn bạn không thể tương tác được vi những window đang chạy trên
desktop không thuc chủ quyền của bạn; cũng có nghĩa là ít nhất VirusScan (và có lẽ hầu hết các
tường lửa cá nhân nữa) cần được tái thiết.
3. Thêm chi tiết nguồn gốc vào các thông điệp, và tùy thuộc vào các ứng trình quyết định có xử
lý thông điệp hay không. Ðiều này cn một giải mở rộng (extension) trong Win32 API, c
đống công việc cho thiên hạ s dụng. Ln chuyện, và thiên hạn vẫn có thể làm sai như thường.
Hãy nhìno c điển hình tràn bộ đệm - loi lỗiy đã có hàng nhiều năm và giờ đây vẫn rt
phổ biến.
Căn bản mà nói, chẳng có một giải pháp đơn gin nào, đây là lý do ti sao Microsoft vẫn ếm kỹ
vấn đề y. Khổ nỗi, nếu tôi kh năng tìm ra lỗiy, tôi dám bảo đảm những người khác
cũng đã tìm ra. Có thể họ đã không cho ai biết và lần sau, khi họ lẻn vào hệ thống của bn như
một guest, bạn sẽ không biết đường trời nào ti sao họ có được LocalSystem t guest. Tận cùng
mà nói, bạn luôn luôn cập nhật với các patches đó chớ?
Phụ lục: Tại sao đây là vấn đề?
Khi Microsoft thy bn sao của bài viết này, họ gởi hồi âm cho tôi nói rõ là họ biết các loi tấn
công y, và họ không xếp loại những lỗi này thuc dạng yếu điểm bảo mật. Tôi tin quan điểm
của họ là đúng. Có hai lý do Microsoft đưa ra a) loi khai thác trên đòi hỏi khả năng tiếp cận
giới hạn đến máy của bạn, hoặc b) loại khai thác trên đòi hỏi bạn chạy một thứ mã đen tối nào
đó trên máy. Tôi hoàn toàn đồng ý cả hai trường hợp, làm chủ máy thì d thc hiện khai thác
rồi. Tuy nhiên, họ bị lạc đề. Kẻ tấn công thể dùng những kỹ thuật trên để gia tăng chủ quyền.
Nếu họ có thể truy cậpo mức độ là guest tới máy, những loi tấn công trên cho phép bạn
thu hoạch chủ quyền LocalSystem từ bất cứ account nào. Có ai đã từng nghe đến một món đồ
ngh nhỏ có cái tên là hk.exe không? Vậy còn ErunAsX (AKA DebPloit)? Và rồi iishack.dll? Tất c
các đồ nghề này khai thác vài lỗi cho phép bạn gia tăng chủ quyền SAU KHI bạn đã truy cập
được vào máy. Tất cả những loại khai thác này đã đưc Microsoft nhận diện và patched.
Trường hợp máy desktop của công ty, thông thường những máy này được khkỹ. Người dùng
trên máy không làm được gì cho lm bởi họ không được phép. Nếu máy đó bị hổng do Shatter
tấn công, người dùng có thể chiếm chủ quyền LocalSystem và làm gì tùy thích. Trường hợp
Terminal Server (hoặc Citrix) còn tệ hại hơn nữa. Th ng tượng một công ty cung cấp khách
hàng các chức năng của dịch vụ terminal vì mục đích nào đó. Công ty đó nhất định KHÔNG cho
người dùng của họ bất cứ một chủ quyềnthật” nào cả. Sự tấn công của Shatter s cho phép các
người dùng kia nắm giữ hoàn toàn máy chủ đó; chủ quyền LocalSystem cao hơn cả
Administrator, và trong mt chia phân máy ch (shared server) đó chính là vấn đ. Ồ, và nó
cũng chẳng đòi hỏi truy cập trên console nữa - Tôi đã thử tấn công một Terminal Server thành
công cách xa vài trăm dặm.
Một thực trạng đơn gin là Microsoft BIẾT rõ họ không thể sửa các lỗi này. chế sử dng trong
Win32 API từ phiên bản NT 3.5 phát hành năm 1993 đã khá “tĩnh. Microsoft không thể thay đổi
nó được. Cách duy nhất họ có thể chặn đứng những tấn công này là không cho phép các ứng
trình chạy trên desktop có chủ quyền cao hơn chủ quyền những ngưi truy cập vào system.
Microsoft tin rng desktop nằm trên biên giới bảo mật, bất kỳ window nào trên desktop đó
được xếp loại là phi tín (untrusted). Ðiều này đúng, nng ch đúng đối với Windows, và cũng
các lỗi trên. Cách này hay cách kia, Microsoft phá vỡ luật của chính họ; có quá nhiều windows
chạy trên desktop vi chủ quyền LocalSystem. Hãy dùng đồ nghề shatter của tôi xác minh
vấn đề y - có c đống windows vô danh cũng có thể chạy với chủ quyn LocalSystem, và nhất
định phi có một ít windowsn (invisible) (chẳng hạn như DDE server) cũng chạy với chủ quyền
LocalSystem. Biên giới bảo mật cái khỉ mốc! (tm dịch trệch đi từ nguyên bảnlý do tế nhị
trong ngôn ngữ).
Phải đây chỉ là vấn đề của Win32?