Lập trình máy kỳ dị
Đồng nghiệp cũ của tôi ở Matasano mới làm một cái game rất thú vị, bạn nào muốn luyện kỹ năng dịch ngược mã và khai thác lỗi bộ nhớ thì nên xem: microcorruption.com.
Lâu lắm rồi tôi mới chơi game dạng này. Hồi trước tôi hay chơi CTF, nhưng mà CTF thường đòi hỏi phải tập trung liên tục trong vài ngày. Có lần tôi chơi liên tục ba ngày hai đêm, ngủ luôn ở công ty, sáng dậy thì đi bộ ra ăn hủ tíu gõ xong về chơi tiếp. Không tắm! Bây giờ thì không làm vậy được nữa. Với lại CTF nhiều khi đòi hỏi phải có những công cụ hay setup mà tôi không có sẵn, nên dần dà tôi cũng không còn mặn mà lắm.
Micro Corruption hay ở chỗ chỉ cần browser là chơi được và muốn chơi lúc nào cũng được. Mỗi ngày tôi chơi 1-2 tiếng, khi nào chán thì thôi, không phải chạy đua thời gian nên khá là thư giãn. Điều mà tôi thích nhất là game này có nhiều màn, bắt đầu từ rất dễ, mãi về sau mới có những mức khó hơn, thành ra mình có thể vừa chơi vừa học. Tôi thích những game mà tôi có thể học được gì đó, hơn là những game đánh đố, khó nhưng không hay.
Tôi chơi hổm rày thì thấy những màn đầu chỉ cần kiến thức cơ bản về cấu trúc máy tính và cách tổ chức bộ nhớ của một tiến trình là có thể làm được. Sau đó sẽ có những màn đòi hỏi phải biết cách khai thác lỗi hỏng bộ nhớ trên stack, trên heap, lỗi tràn số nguyên hay lỗi format string. Những màn gần cuối sẽ có thêm những trở ngại phải vượt qua như DEP, ASLR, shellcode chỉ được chứa ký tự alphabet, v.v Nhìn chung là tất cả những hướng tấn công mà chúng ta biết đến, cách phòng chống thông thường và cách vượt qua chúng đều được đưa vào game.
Chơi game này dễ ghiền, vì nó cho ta cảm giác ta có thể kiểm soát tất cả mọi thứ. Tôi nghĩ đây cũng là điều làm cho ngành security, mà đặc biệt là lĩnh vực khai thác lỗi phần mềm, trở nên cực kỳ hấp dẫn. Bạn lấy một chương trình, chẳng cần mã nguồn, mở tung nó ra để rồi hiểu nó còn hơn cả người viết ra nó. Bạn chạy chương trình, gửi cho nó một đoạn dữ liệu và ngay lập tức kiểm soát được lệnh tiếp theo mà chương trình sẽ chạy. Nhưng mọi chuyện chưa dừng ở đây, mà cuộc vui thật sự chỉ mới bắt đầu.
Bạn cần phải lập trình lại chương trình ban đầu. Ví dụ như khi dùng Mobile Safari trên một số phiên bản iPhone để truy cập vào www.jailbreakme.com thì Safari không còn là trình duyệt nữa, mà trở thành công cụ jailbreak tự động. Bản thân Safari không thể làm việc này, nhưng nó đã được comex lập trình lại. Vào năm 2010 Safari cũng đã từng được lập trình lại để tải hết tin nhắn SMS lên một máy chủ. Chrome cũng không thoát khỏi số phận bị lập trình lại, mặc cho các kỹ sư Google đã dày công bày binh bố trận bảo vệ.
Rõ ràng lập trình lại một chương trình đang chạy không phải là chuyện đơn giản. Bạn cần phải biết (một phần) trạng thái của chương trình: giá trị của các register, trên stack và heap đang có những gì, các biến toàn cục và cục bộ đang có giá trị gì, v.v. rồi bắt chương trình chạy lệnh theo ý mình và chuyển qua một trạng thái tiếp theo. Nhưng nhập lệnh gì và như thế nào?
Một ví dụ cơ bản: bạn muốn gọi một hàm và truyền vào cho nó một chuỗi (ví dụ như gọi hàm system, truyền vào con trỏ đến chuỗi /bin/sh để lấy shell), nhưng tại thời điểm bạn kiểm soát được chương trình thì stack trông như thế này:
Bạn kiểm soát được nội dung những ô màu xanh, nhưng không kiểm soát được ô màu trắng. Nói cách khác bạn cần phải chạy được những lệnh để chuyển con trỏ stack (esp) về vùng nhớ mà bạn kiểm soát được. Có nhiều cách để làm được việc này - một cách đơn giản là trỏ eip (con trỏ chứa địa chỉ dòng lệnh tiếp theo của chương trình) vào một đoạn chương trình có nội dung là
pop
pop
pop
ret
Mỗi lệnh pop sẽ chuyển esp lên một ô, ba lệnh pop sẽ chuyển esp lên ô màu xanh đầu tiên, lệnh ret sẽ lấy giá trị của ô này gán cho eip. Nhưng đoạn "pop, pop, pop, ret" ở đâu ra? Bạn có thể nhập vào, hoặc hay hơn là sử dụng lại chính mã của chương trình mà bạn đang muốn kiểm soát. Kỹ thuật này đã được sử dụng từ rất lâu và gần đây được gọi là return-oriented programming. Ở Việt Nam có mấy anh ở VNSECURITY là chuyên gia trong lĩnh vực này.
Tựu trung lại thì cái máy mà bạn cần phải lập trình rất dị thường: trạng thái đầu vào, dữ liệu có thể nhập vô, định dạng của chúng, trạng thái đầu ra, tập lệnh có thể chạy được, v.v. tất cả những thông tin mà bình thường bạn sẽ biết có thể sẽ rất mù mờ và chính bạn phải lần mò tìm ra chúng bằng cách dịch ngược mã chương trình. Có khi một phần chương trình mục tiêu cũng bị che đi và bạn phải dùng một lỗi ở phần chương trình đã biết để tải về mã của phần chương trình chưa biết. Trong mớ bòng bong này, bạn phải khiến chương trình làm được một việc gì đó hữu ích cho bạn! Chào mừng đến với nghệ thuật lập trình máy kỳ dị.
--
Tôi nghĩ dùng Micro Corruption làm giáo trình dạy kiến trúc máy tính thì hay tuyệt. Nếu mấy anh ở Matasano đồng ý, tôi sẽ thu xếp dùng cái này để mở một lớp trực tuyến miễn phí về kiến trúc máy tính và khai thác lỗi phần mềm. Sách để đọc là cuốn Computer Systems: A Programmer's Perspective mà tôi đã có giới thiệu trước đây. Tôi sẽ thông báo khi nào chuẩn bị xong.
Lâu lắm rồi tôi mới chơi game dạng này. Hồi trước tôi hay chơi CTF, nhưng mà CTF thường đòi hỏi phải tập trung liên tục trong vài ngày. Có lần tôi chơi liên tục ba ngày hai đêm, ngủ luôn ở công ty, sáng dậy thì đi bộ ra ăn hủ tíu gõ xong về chơi tiếp. Không tắm! Bây giờ thì không làm vậy được nữa. Với lại CTF nhiều khi đòi hỏi phải có những công cụ hay setup mà tôi không có sẵn, nên dần dà tôi cũng không còn mặn mà lắm.
Micro Corruption hay ở chỗ chỉ cần browser là chơi được và muốn chơi lúc nào cũng được. Mỗi ngày tôi chơi 1-2 tiếng, khi nào chán thì thôi, không phải chạy đua thời gian nên khá là thư giãn. Điều mà tôi thích nhất là game này có nhiều màn, bắt đầu từ rất dễ, mãi về sau mới có những mức khó hơn, thành ra mình có thể vừa chơi vừa học. Tôi thích những game mà tôi có thể học được gì đó, hơn là những game đánh đố, khó nhưng không hay.
Tôi chơi hổm rày thì thấy những màn đầu chỉ cần kiến thức cơ bản về cấu trúc máy tính và cách tổ chức bộ nhớ của một tiến trình là có thể làm được. Sau đó sẽ có những màn đòi hỏi phải biết cách khai thác lỗi hỏng bộ nhớ trên stack, trên heap, lỗi tràn số nguyên hay lỗi format string. Những màn gần cuối sẽ có thêm những trở ngại phải vượt qua như DEP, ASLR, shellcode chỉ được chứa ký tự alphabet, v.v Nhìn chung là tất cả những hướng tấn công mà chúng ta biết đến, cách phòng chống thông thường và cách vượt qua chúng đều được đưa vào game.
Chơi game này dễ ghiền, vì nó cho ta cảm giác ta có thể kiểm soát tất cả mọi thứ. Tôi nghĩ đây cũng là điều làm cho ngành security, mà đặc biệt là lĩnh vực khai thác lỗi phần mềm, trở nên cực kỳ hấp dẫn. Bạn lấy một chương trình, chẳng cần mã nguồn, mở tung nó ra để rồi hiểu nó còn hơn cả người viết ra nó. Bạn chạy chương trình, gửi cho nó một đoạn dữ liệu và ngay lập tức kiểm soát được lệnh tiếp theo mà chương trình sẽ chạy. Nhưng mọi chuyện chưa dừng ở đây, mà cuộc vui thật sự chỉ mới bắt đầu.
Bạn cần phải lập trình lại chương trình ban đầu. Ví dụ như khi dùng Mobile Safari trên một số phiên bản iPhone để truy cập vào www.jailbreakme.com thì Safari không còn là trình duyệt nữa, mà trở thành công cụ jailbreak tự động. Bản thân Safari không thể làm việc này, nhưng nó đã được comex lập trình lại. Vào năm 2010 Safari cũng đã từng được lập trình lại để tải hết tin nhắn SMS lên một máy chủ. Chrome cũng không thoát khỏi số phận bị lập trình lại, mặc cho các kỹ sư Google đã dày công bày binh bố trận bảo vệ.
Rõ ràng lập trình lại một chương trình đang chạy không phải là chuyện đơn giản. Bạn cần phải biết (một phần) trạng thái của chương trình: giá trị của các register, trên stack và heap đang có những gì, các biến toàn cục và cục bộ đang có giá trị gì, v.v. rồi bắt chương trình chạy lệnh theo ý mình và chuyển qua một trạng thái tiếp theo. Nhưng nhập lệnh gì và như thế nào?
Một ví dụ cơ bản: bạn muốn gọi một hàm và truyền vào cho nó một chuỗi (ví dụ như gọi hàm system, truyền vào con trỏ đến chuỗi /bin/sh để lấy shell), nhưng tại thời điểm bạn kiểm soát được chương trình thì stack trông như thế này:
Bạn kiểm soát được nội dung những ô màu xanh, nhưng không kiểm soát được ô màu trắng. Nói cách khác bạn cần phải chạy được những lệnh để chuyển con trỏ stack (esp) về vùng nhớ mà bạn kiểm soát được. Có nhiều cách để làm được việc này - một cách đơn giản là trỏ eip (con trỏ chứa địa chỉ dòng lệnh tiếp theo của chương trình) vào một đoạn chương trình có nội dung là
pop
pop
pop
ret
Mỗi lệnh pop sẽ chuyển esp lên một ô, ba lệnh pop sẽ chuyển esp lên ô màu xanh đầu tiên, lệnh ret sẽ lấy giá trị của ô này gán cho eip. Nhưng đoạn "pop, pop, pop, ret" ở đâu ra? Bạn có thể nhập vào, hoặc hay hơn là sử dụng lại chính mã của chương trình mà bạn đang muốn kiểm soát. Kỹ thuật này đã được sử dụng từ rất lâu và gần đây được gọi là return-oriented programming. Ở Việt Nam có mấy anh ở VNSECURITY là chuyên gia trong lĩnh vực này.
Tựu trung lại thì cái máy mà bạn cần phải lập trình rất dị thường: trạng thái đầu vào, dữ liệu có thể nhập vô, định dạng của chúng, trạng thái đầu ra, tập lệnh có thể chạy được, v.v. tất cả những thông tin mà bình thường bạn sẽ biết có thể sẽ rất mù mờ và chính bạn phải lần mò tìm ra chúng bằng cách dịch ngược mã chương trình. Có khi một phần chương trình mục tiêu cũng bị che đi và bạn phải dùng một lỗi ở phần chương trình đã biết để tải về mã của phần chương trình chưa biết. Trong mớ bòng bong này, bạn phải khiến chương trình làm được một việc gì đó hữu ích cho bạn! Chào mừng đến với nghệ thuật lập trình máy kỳ dị.
--
Tôi nghĩ dùng Micro Corruption làm giáo trình dạy kiến trúc máy tính thì hay tuyệt. Nếu mấy anh ở Matasano đồng ý, tôi sẽ thu xếp dùng cái này để mở một lớp trực tuyến miễn phí về kiến trúc máy tính và khai thác lỗi phần mềm. Sách để đọc là cuốn Computer Systems: A Programmer's Perspective mà tôi đã có giới thiệu trước đây. Tôi sẽ thông báo khi nào chuẩn bị xong.
Comments