Sau một thời gian nghiên cứu về Phar Deserialization, hôm nay mình xin chia sẻ một cách khái quát về lỗ hổng này hướng tới các bạn mới bắt đầu tìm hiểu. Kỹ thuật mới này được trình bày bởi Sam Thomas  tại hội nghị Black Hat, có thể thực thi mã từ xa thông qua lỗ hổng Deserialization trong PHP. Bài viết được chia thành ba phần: Giới thiệu về Deserialization vulnerability, Phar deserialization và Khai thác. Với những ai đã biết về Deserialization vulnerability các bạn của thể bắt đầu đọc luôn từ phần hai.

 

Deserialization vulnerability

Serialization là quá trình xử lý, chuyển đổi các thuộc tính của một đối tượng thành một định dạng dữ liệu ví dụ như binary fomat, từ đó có thể lưu trên ổ đĩa, hoặc sử dụng vào các mục đích cần thiết khác, còn quá trình Deserialization là quá trình ngược lại

Lỗ hổng Deserialization trong PHP hay còn gọi là PHP Object Injection, có thể giúp kẻ tấn công thực hiện nhiều loại tấn công khác nhau như:  Code InjectionSQL Injection, DoS,… tùy vào từng trường hợp cụ thể

Để thực hiện khai thác thành công lỗ hổng này trên nền tảng PHP ta cần 2 điều kiện sau:

  1.  Đối tượng cần tấn công phải có lớp sử dụng Magic method
  2.  Tìm được POP chain, hay chính là có thể tùy chỉnh được các đoạn code trong quá trình hàm unserialize() được gọi

Cùng xét các ví dụ sau về Magic method và POP chain

Magic method

Magic method là các function đặc biệt trong các lớp của PHP, tên của các function này có hai dấu gạch dưới đứng trước, nó sẽ được gọi ngầm ở một sự kiện cụ thể, ví dụ như: __sleep(), __toString(), __construc(), …. Phần lớn trong số các function này sẽ không làm gì nếu không có sự khai báo, thiết lập của người lập trình. Ở đây có hai Magic method có thể trigger được lỗi Phar Deserialization mà ta cần quan tâm đến là:

__wakeup():  Được gọi khi một đối tượng được deserialize

__destruct(): Được gọi khi một kịch bản PHP kết thúc hoặc một đối tượng không còn được dùng trong code nữa và bị hủy bỏ

Hình 1

Hình 2

Đoạn code tại Hình 1 và kết quả ở Hình 2 đã cho thấy function __wakeup() được gọi ngay sau khi  một đối tượng thuộc lớp Test được deserialize, và khi kết thúc đoạn kịch bản PHP trên, function __destruct() cũng ngay lập tức được gọi ngầm.

POP chain

Hình 3

 Đoạn code trên là một POP chain được tạo bởi 3 gadgets có thể dẫn tới RCE và có thể được biểu diễn bởi sơ đồ sau:

Hình 4

  •    Đầu tiên chúng ta chèn một đối tượng “Mail” vào thuộc tính “$writer” , tại dòng code số 8 sẽ gọi đến phương thức “shutdown()” của lớp “Mail”
  •    Tương tự chèn một đối tượng “Sendmail” vào thuộc tính “$transport” , tại đó dòng code số 18 sẽ gọi đến phương thức “send()” của lớp “Sendmail
  •    Ta thay đổi giá trị của hai thuộc tính “$callable = exec”“$to = calc”
  •    Cuối cùng hàm call_user_func() được gọi như sau call_user_func (“exec”, “calc”) và ứng dụng Calculator trong hệ điều hành Window được tự động mở lên

Kẻ tấn công sẽ hoàn toàn truyền vào những tham số khác gây nguy hiểm hơn

Phar Deserialization

Trước khi đi vào lỗ hổng Phar Deserialization là gì, hãy cùng tìm hiểu xem Phar là gì.

Phar file trong PHP tương tự như Jar file trong Java là một package format cho phép ta gói nhiều các tập code, các thư viện, hình ảnh,… vào một tệp

Cấu trúc một Phar file gồm có:

  • Stub: đơn giản chỉ là một file PHP và ít nhất phải chứa đoạn code sau: <?php __HALT_COMPILER();
  • A manifest (bảng kê khai): miêu tả khái quát nội dung sẽ có trong file
  • Nội dung chính của file
  • Chữ ký: để kiểm tra tính toàn vẹn (cái này là optional, có hay không cũng được)

Điểm đáng chú ý nhất trong cấu trúc của một Phar file đó là phần manifest, theo Manual của PHP thì trong mỗi một Phar file, phần manifest có chứa các thông tin sau:

Hình 5

Dòng được bôi vàng cho biết phần manifest này sẽ giữ các Meta-data đã được serialize. Một điều thú vị là nếu một filesystem function gọi đến một Phar file thì tất cả các Meta-data trên sẽ được tự động unserialize

Dưới đây là danh sách các filesystem function có thể trigger lỗ hổng này:

Hình 6

Khai thác

Như vậy để khai thác lỗ hổng này cần 3 điều kiện sau:

  1.  Tìm được POP chain trong trong source code cần khai thác
  2.  Đưa được Phar file vào đối tượng cần khai thác
  3.  Tìm được entry point, đó là những chỗ mà các filesystem function gọi tới các Phar file do người dùng kiểm soát

Tiến hành thực hiện khai thác lỗ hổng Phar deserialization trên Zend Framework

  • Đầu tiên làm việc có vẻ dễ dàng nhất đó là đi tìm entry point

Hình 4

Hình 5

Ta có thể thấy entry point nằm ở dòng 166 Hình 4 khi hàm “file_exists()” (một filesystem function) được gọi có tham số truyền vào là “$url” được gửi lên bởi người dùng (Hình 5, dòng 87)

  • Tiếp tới là tìm một POP chain, việc này thường chỉ có thể hoàn thành bằng việc review code hoặc các bạn cũng có thể sử dụng các POP chain có sẵn tại PHPGGC  của tác giả Sam Thomas (@_s_n_t). Đây là thư viện cùng với tool để tạo ra các unserialize payload, tương tự như Ysoserial của  Chris Frohoff dành cho Java, chỉ khác là PHPGGC dành cho PHP

Dưới đây là POP chain của mình, tiến hành dựng lại tất cả các Class, serialize và đẩy vào phần manifest của Phar file

Hình 6

Vậy là chúng ta đã có một Phar file tên “test.phar” chứa các đoạn mã không an toàn, việc còn lại là tiến hành đẩy file này vào chỗ cần khai thác và chạy nó thôi. Chúng ta có thể tham khảo thủ thuật chuyển Phar file vào một file ảnh JPG giả của Sam Thomas tại đây

Hình 7

Cảm ơn các bạn đã đọc bài viết của mình, mong rằng các bạn đã phần nào đó có thêm kiến thức về lỗ hổng này. Ở những phần sau mình sẽ có những phân tích chi tiết hơn. Rất vui nếu nhận được các ý kiến đóng góp từ mọi người!

Trung tâm An toàn thông tin

4.344 lượt xem