Hướng dẫn php object injection ctf - ctf tiêm đối tượng php

Đây là hướng dẫn cho Thử thách tiêm đối tượng PHP từ CTF công nghiệp Kaspersky được tổ chức bởi Kaspersky Lab.

Trong thử thách này, có một hình thức thực hiện hoạt động số học theo đầu vào được cung cấp của người dùng.

Hãy thực hiện trường hợp sử dụng bình thường trước. Tôi đã nhập 2 và 3 trong các hộp văn bản thứ nhất, thứ hai tương ứng.

Như chúng ta có thể thấy, chúng ta có kết quả của biểu thức 2 + 3 = 5 của chúng ta.

Đơn giản và đơn giản, nhưng một điều khiến tôi chú ý là mã thông báo. Hãy thử nhấp vào nút Chia sẻ trên mạng.

Đã đưa ra yêu cầu GET với tham số Token Token. Hãy nhìn vào phản ứng.

Nó có cùng một biểu thức mà trước đây chúng ta đã tính toán 2 + 3 = 5.

Sau khi giải mã mã thông báo dưới dạng base64, tôi có một đối tượng PHP tuần tự hóa.base64 i Got a serialized PHP object.

Như chúng ta có thể thấy, chúng ta có một hàm tổng và đối số (mảng) là 2 và 3. Bây giờ có rất nhiều nội dung để tiêm đối tượng PHP trên web. Tôi đã trải qua hầu hết tất cả. Mặc dù bạn có thể nhìn vào nó.

Bây giờ tôi đã làm rất nhiều thử nghiệm và lỗi, không đăng tất cả ở đây vì lợi ích của bài viết này.

Hãy để một cái nhìn vào đối tượng tuần tự hóa của chúng tôi

O: 10: Biểu thức của người Hồi giáo: 3: {s: 14: Biểu thức của người Hồi 1; D: 3;} S: 9: Chuỗi Stringify;s:3:”sum”;s:18:”Expressionparams”;a:2:{i:0;d:2;i:1;d:3;}s:9:”stringify”;s:5:”2 + 3";}

Bạn có thể chơi với đối tượng tuần tự này và xem cách cư xử của nó.

Tôi đã nghi ngờ rằng, Sum Sum là một hàm do người dùng xác định và Expressionparams là mảng có giá trị thứ nhất là giá trị 2 và thứ hai là 3.“sum” is a user defined function and “Expressionparams” is array which has first value as 2 and second value as 3.

Bạn có thể gọi bất kỳ chức năng PHP nào thay cho hàm tổng.sum function.

Tôi đã thay đổi hàm tổng thành hệ thống () là hàm PHP thực thi

O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
1 đã cho và đưa ra kết quả.sum function to system() which is a PHP function that executes the given
O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
1 and outputs the result.

O: 10: Biểu thức của người Hồi giáo: 3: {s: 14: Biểu thức của người Hồi 1; D: 3;} S: 9: Chuỗi Stringify;s:6:”system”;s:18:”Expressionparams”;a:2:{i:0;d:2;i:1;d:3;}s:9:”stringify”;s:5:”2 + 3";}

Hãy nhớ rằng chúng ta cần cập nhật độ dài của chuỗi từ 3 lên 6. vì độ dài của tên hàm của chúng ta là 6 (hệ thống).3 to 6. because length of our function name is 6(system).

S: 3: ”Sum”

S: 6: Hệ thống ”

Và hơn là mã hóa nó một lần nữa với base64

Hãy gửi yêu cầu với tải trọng mới.

Mát mẻ!! Chúng tôi đã đúng, chúng tôi có thể vượt qua bất kỳ chức năng PHP nào trong đối tượng tuần tự hóa này, điều duy nhất còn lại là cung cấp các tham số ở định dạng đúng. Sum có mảng làm đối số, chúng tôi cần chuỗi làm đối số cho chức năng hệ thống của chúng tôi.system function.

Tôi đã thay thế a: 2: {i: 0; d: 2; i: 1; d: 3;} (mảng)a:2:{i:0;d:2;i:1;d:3;} (array)

with

S: 2: LS LS (chuỗi)(string)

Hãy thử chạy lệnh LS.LS command.

BINGO!!

Nhiệm vụ cuối cùng phía trước của chúng tôi là tìm thấy lá cờ, điều này không quá khó khăn.

Cho phép mở tệp fl4g_h4r3.fl4g_h4r3 file.

Và cuối cùng chúng tôi đã nhận được cờ. Cảm ơn vì đã đọc.

#SharingIsCaring

Hãy để kết nối trên Twitter

Hướng dẫn php object injection ctf - ctf tiêm đối tượng php

Giống như JAVA, PHP giờ đây cũng đã hỗ trợ Object-Oriented Programming (OOP hay hướng đối tượng). Lập trình hướng đối tượng giúp lập trình viên kế thừa mã nguồn một cách hiêu quả hơn so với lập trình hướng cấu trúc. Không chỉ dừng lại với việc kế thừa mã nguồn, lập trình hướng đối tượng còn có các ưu điểm khác được thể hiện thông qua 4 tính chất của OOP như:Object-Oriented Programming (OOP hay hướng đối tượng). Lập trình hướng đối tượng giúp lập trình viên kế thừa mã nguồn một cách hiêu quả hơn so với lập trình hướng cấu trúc. Không chỉ dừng lại với việc kế thừa mã nguồn, lập trình hướng đối tượng còn có các ưu điểm khác được thể hiện thông qua 4 tính chất của OOP như:

  • Tính đóng gói (encapsulation)
  • Tính kế thừa (Inheritance)
  • Tính đa hình (polymorphism)
  • Tính trừu tượng (abstraction)

Để hiểu thêm về 4 tính chất trong OOP có thể đễ dàng tìm kiếm trên google hoặc có thể tham khảo tại đây: https://www.codehub.com.vn/4-tinh-chat-cua-lap-trinh-huong-doi-tuong-trong-Java

Trong lập trình hướng đối tượng chương trình được tổ chức theo các lớp (Class). Lớp được hiểu như một khuôn mẫu của một đối tượng trong thực tế có thuộc tính (biến trong lập trình hướng cấu trúc) và phương thức (hàm trong lập trình hướng cấu trúc). Khi muốn thực hiện công việc nào đó ta sẽ tạo các thực thể của một lớp thể thực hiện công việc mong muốn.

Lớp cũng là một kiểu dữ liệu nhưng nó khác với các kiểu dữ liệu nguyên thủy đã biết như số nguyên (integer), chuỗi (string), boolean, do lớp chứa thuộc tính và phương thức. Vì vậy, để có thể lưu trữ, truyền tải qua mạng thì ta cần có một quy tắc để chuyển lớp sang dạng có thể lưu trữ cũng như có thể gửi qua các phương tiện truyền thông được. Để thực hiện điều đó PHP đưa ra 2 hàm: serialize, unserialize.

  • serialize có nhiệm vụ chuyển một đối tượng sang dạng chuỗi để có thể lưu trữ cũng như gửi qua mạng.
  • Unserialize chuyển chuỗi sang đối tượng tương ứng.

Để hiểu được tại sao lại có lỗ hổng này trước hết ta sẽ tìm hiểu hoạt động của hàm serialize và unserialize. Sau đó, ta sẽ tiến hành thực dụng lab demo lỗ hổng.

Hoạt động của hàm serialize

Như đã nói qua ở trên, hàm serialize nhận đầu vào là một đối tượng và đầu ra là một chuỗi tương ứng với dữ liệu đầu vào. Để hình dung rõ hơn ta thực hiện một ví dụ nhỏ.


    class User{
        public $username;
        public $status;
    }
    
    $user = new User;
    $user->username = 'cm0s';
    $user->status = 'labs';
    echo serialize($user);
?>

kết quả hiển thị ra

O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}

Kết quả chuyển đổi từ object sang chuỗi phải tuân theo một cấu trúc nhất định.

cấu trúc serialize

Cấu trúc serialize trong PHP có dạng

O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
2. Ví dụ,
O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
3 là kiểu dữ liệu boolean

b:THE_BOOLEAN;

O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
4 là số nguyên

i:THE_INTEGER;

O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
5 là số thực

d:THE_FLOAT;

O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
6 là kiểu chuỗi

s:độ-dài-chuỗi:"giá trị";

O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
7 là mảng

a:số-lượng-phần-tử:{các-phần-tử}

Cuối cùng

O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
8 đại diện cho một đối tượng.

O:độ-dài-lớp:"tên-lớp":số-lượng-thuộc-tính:{các-thuộc-tính}

Dựa vào mô tả cấu trúc trên ta dễ dàng hiểu được tại sao sau khi serialize lại có đầu ra là một chuỗi dài như trên.

Hoạt động của hàm unserialize

Ngược lại với hàm serialize, hàm unserialize nhận đầu vào là một chuỗi tuân theo cấu trúc serialize chuyển thành một đối tượng tương ứng. Thêm phần trực quan ta xem thêm một đoạn code nhỏ nữa.


	class User{
		public $username;
		public $status;
	}

	$user = new User;
	$user->username = 'cm0s';
	$user->status = 'labs';
	$serialized_string = serialize($user);
	$unserialized_data = unserialize($serialized_string);
	var_dump($unserialized_data);
	var_dump($unserialized_data->status);
?>

Với đoạn code trên sẽ cho ra kết quả như sau

Hướng dẫn php object injection ctf - ctf tiêm đối tượng php

Đến đây ta đã hiểu được cơ bản hướng đối tượng hay OOP là gì. Và cũng hiểu được cách để serialize và unserialize đối tượng như nào. Tiếp theo ta sẽ tìm hiểu tại sao khi unserialize lại có thể bị khai thác và tìm hiểu lý do tại sao. Đầu tiên ta sẽ tìm hiểu một vài magic method (mình để nguyên vì khi dịch ra tiếng Việt không hay) trong PHP. Những hàm này là một phần nguyên nhân dẫn đến việc PHP deserialization bị khai thác.magic method (mình để nguyên vì khi dịch ra tiếng Việt không hay) trong PHP. Những hàm này là một phần nguyên nhân dẫn đến việc PHP deserialization bị khai thác.

__wakeup() là phương thức trong class được thực thi khi một object được gọi dậy. Trong trường hợp cụ thể này là khi hàm unserializtion chạy xong. là phương thức trong class được thực thi khi một object được gọi dậy. Trong trường hợp cụ thể này là khi hàm unserializtion chạy xong.

__destruct() phương thức trong class được thực hiện khi một object bị hủy bỏ hay không còn tồn tại trong chương trình nữa. phương thức trong class được thực hiện khi một object bị hủy bỏ hay không còn tồn tại trong chương trình nữa.

Khai thác lỗ hổng PHP deserialization

Lỗ hổng PHP deserialization có thể giúp ta thực hiện được các tấn công như SQL injection, path traversal, code injection,... Tùy code bị lỗi như nào.

Để khai thác được lỗ hổng PHP deserialization cần có 2 điều kiện.

  1. Class phải sử dụng 1 trong 2 hàm __wakeup(), __destruct() để xử lý dữ liệu người dùng.__wakeup(), __destruct() để xử lý dữ liệu người dùng.
  2. Người dùng có thể chèn dữ liệu độc hại vào hàm unserialize().unserialize().

Để cho tường minh thêm ta sẽ làm thêm một ví dụ nữa.

 class User {
        private $role;

        function __construct($role) {
            $this->role = $role;
        }

        function __wakeup() {
            if (isset($this->role)) eval($this->role);
        }
    }

$user_data = unserialize($_COOKIE['data']);

Ta cùng phân tích qua đoạn code trên xác định lỗ hổng và khả năng khai thác.

  1. Đoạn code trên nhận dữ liệu từ người dùng nhập vào (lấy dữ liệu qua $_GET) mà không thực hiện bất kỳ biện pháp làm sạch hay lọc dữ liệu. Nên ta có thể chèn dữ liệu độc hại vào.$_GET) mà không thực hiện bất kỳ biện pháp làm sạch hay lọc dữ liệu. Nên ta có thể chèn dữ liệu độc hại vào.
  2. Class PHPdeserialization có sử dụng hàm __wakeup() để thực thi dữ liệu người dùng truyền vào.PHPdeserialization có sử dụng hàm __wakeup() để thực thi dữ liệu người dùng truyền vào.

Từ 2 điều trên ta đã xác định được đoạn code trên có lỗi PHP deserialization. Lỗi này giúp ta thực hiện tấn công code injection do sử dụng hàm eval() để xử lý dữ liệu của người dùng nhập vào mà không thực hiện làm sạch.eval() để xử lý dữ liệu của người dùng nhập vào mà không thực hiện làm sạch.

Để thực hiện khai thác ta sẽ chèn payload sau vào COOKIE với thên data.COOKIE với thên data.

O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
0

Kết quả là ra ta thực hiện được code PHP :-^

Hướng dẫn php object injection ctf - ctf tiêm đối tượng php

Qua bài ta hiểu cơ bản được thế nào là hướng đối tượng, và nguyên nhân và điều kiện để khai thác lỗi PHP deserialization. Tìm hiểu một ví dụ cơ bản khai thác lỗi này.

Giờ thì xin chào và tạm biệt!

Tham khảo

  • php unserialize
  • php magic
  • https://medium.com/swlh/exploiting-php-deserialization-56d71f03282a