🔐Insucure deserialization

Advanced topics

Serialization là gì?

Serialization là quá trình chuyển đổi cấu trúc phức tạp như object hay các field thành một dạng ngắn gọn hơn dễ truyền đi và quá trình truyền qua mạng, nó có thể ở dạng byte, XML, JSON,…

Việc Serialization giúp cho:

  • Ghi dữ liệu phức tạp vào bộ nhớ liên quá trình, tệp hoặc cơ sở dữ liệu trở nên dễ dàng hơn

  • Gửi dữ liệu phức tạp, ví dụ, qua mạng, giữa các thành phần khác nhau của ứng dụng hoặc trong lệnh gọi API sẽ nhanh hơn, không phức tạp

Deserialization là gì?

Deserialization là quá trình khôi phục luồng byte, XML, JSON... thành một bản sao đầy đủ chức năng của object ban đầu, ở trạng thái chính xác như khi nó được Serialization. Sau đó, logic của trang web có thể tương tác với object được deserialized này, giống như với bất kỳ object nào khác.(Dễ hiểu hơn bạn encode nó đi để gửi thì phải decode nó lại để dễ hiểu, kiểu như thế).

Deserialization không an toàn như nào ?

Deserialization không an toàn là khi dữ liệu có thể kiểm soát của người dùng được giải mã bởi một trang web. Điều này có khả năng cho phép kẻ tấn công thao túng các object được serialization để chuyển dữ liệu có hại vào mã ứng dụng.

Thậm chí có thể thay thế một object được serialization bằng một object thuộc một lớp hoàn toàn khác. Đáng báo động là các object thuộc bất kỳ lớp nào có sẵn trên trang web sẽ được giải mã và khởi tạo, bất kể lớp nào được mong đợi. Vì lý do này, giải mã không an toàn đôi khi được gọi là lỗ hổng "object injection".(PHP Object injection, ....)

Một object của một lớp không mong muốn có thể gây ra một ngoại lệ. Nhiều cuộc tấn công dựa trên deserialization được hoàn thành trước khi quá trình deserialization kết thúc. Điều này có nghĩa là bản thân quá trình deserialization có thể bắt đầu một cuộc tấn công, ngay cả khi chức năng của chính trang web không tương tác trực tiếp với object độc hại. Vì lý do này, các trang web có logic dựa trên các ngôn ngữ được đánh máy mạnh cũng có thể dễ bị ảnh hưởng bởi các kỹ thuật này.

Hậu quả của insecure deserialization là gì ?

Tác động của quá trình khử bay không an toàn có thể rất nghiêm trọng vì nó cung cấp một điểm vào một bề mặt tấn công gia tăng ồ ạt. Nó cho phép kẻ tấn công sử dụng lại mã ứng dụng hiện có theo những cách có hại, dẫn đến nhiều lỗ hổng khác, thường là thực thi mã từ xa(RCE))

Ngay cả trong những trường hợp không thể thực thi mã từ xa, quá trình giải mã hóa không an toàn có thể dẫn đến leo thang đặc quyền(privilege escalation), truy cập tệp tùy ý và tấn công từ chối dịch vụ.

Khai thác lỗ hổng insecure deserialization

Ở đây, mình chỉ viết rõ ra cách lab xử lý deserialization bằng PHP, JAVA, RUBY. Vì các ngôn ngữ này phá phổ biến và nó được serialization khá nhiều, như một bài mình có làm về lỗ hổng trong framework bottle của python cũng có lỗ hổng insecure deserialization thực thi RCE từ cookie nhưng trong trường hợp chúng ta có Secret_key...

Mình nói qua cách xác định được một trang web có dính deserialization không an toàn bằng cách, check xem ở h....

Định dạng PHP deserialization

PHP sử dụng định dạng chuỗi hầu như con người có thể đọc được, với các chữ cái đại diện cho kiểu dữ liệu và số đại diện cho độ dài của mỗi mục nhập. Ví dụ: Object User có các thuộc tính:

$user->name = "carlos";
$user->isLoggedIn = true;

Khi được serialize thì nó sẽ như sau:

O:4:"User":2:{s:4:"name":s:6:"carlos"; s:10:"isLoggedIn":b:1;}
  • O : là object có length là 4: user, trong user có 2 giá trị là name và isLoggedIn

  • S : là chuỗi có length là 4: user, tiếp theo s value có length là 6: carlos và cái tiếp theo tương tự, còn giá trị của isLoggedIn là boolean b:1 - 1 là true, 0 là false

Các phương thức gốc để tuần tự hóa PHP là serialize()unserialize(). Nếu có quyền truy cập mã nguồn, chúng ta tìm kiếm bất kỳ vị trí unserialize()nào trong mã và xem xét thêm nó có khai thác được không.

Định dạng JAVA deserialization

Một số ngôn ngữ, chẳng hạn như Java, sử dụng các định dạng serialization nhị phân. Điều này khó đọc hơn, nhưng bạn vẫn có thể xác định dữ liệu được tuần tự hóa nếu biết cách nhận ra một vài dấu hiệu nhận biết. Ví dụ: các object Java được tuần tự hóa luôn bắt đầu bằng các byte giống nhau, được mã hóa như ac ed trong hệ thập lục phân và rO0trong Base64.

Bất kỳ lớp nào thực hiện giao diện java.io.Serializablecó thể được serialize và deserialize. Nếu bạn có quyền truy cập source code, hãy lưu ý bất kỳ mã nào sử dụng readObject()phương thức, được sử dụng để đọc và deserialize dữ liệu từ một InputStream

Sửa đổi thuộc tính đối tượng(Object attributes)

Khi giả mạo dữ liệu, miễn là kẻ tấn công bảo tồn một object được serialize hợp lệ, quá trình deserialization sẽ tạo ra một đối tượng(Object) phía máy chủ với các giá trị thuộc tính đã sửa đổi.

Ví dụ đơn giản, hãy xem xét một trang web sử dụng object User được serialize để lưu trữ dữ liệu về phiên của người dùng trong cookie. Nếu kẻ tấn công phát hiện object được tuần tự hóa này trong một yêu cầu HTTP, chúng có thể deserialize nó để tìm luồng byte sau:

O:4:"User":2:{s:8:"username";s:6:"carlos";s:7:"isAdmin";b:0;}

Thuộc tính isAdminlà một điểm quan tâm rõ ràng. Kẻ tấn công có thể chỉ cần thay đổi giá trị boolean của thuộc tính thành 1(true), serialize lại object và ghi đè cookie hiện tại của chúng bằng giá trị đã sửa đổi này. Trong trường hợp cô lập, điều này không có tác dụng. Tuy nhiên, giả sử trang web sử dụng cookie này để kiểm tra xem người dùng hiện tại có quyền truy cập vào chức năng quản trị nhất định hay không:

$user = unserialize($_COOKIE);
if ($user->isAdmin === true) {
// cho phép truy cập giao diện admin

Sử đổi kiểu dữ liệu (data types)

Logic dựa trên PHP đặc biệt dễ bị ảnh hưởng bởi kiểu thao tác này do hành vi của toán tử so sánh lỏng lẻo ( ==) khi so sánh các kiểu dữ liệu khác nhau. Ví dụ: nếu bạn thực hiện một phép so sánh lỏng lẻo giữa một số nguyên và một chuỗi, PHP sẽ cố gắng chuyển đổi chuỗi thành một số nguyên, nghĩa là 5 == "5"đánh giá thành true.

Bất thường, điều này cũng hoạt động đối với bất kỳ chuỗi chữ và số nào bắt đầu bằng một số. Trong trường hợp này, PHP sẽ chuyển đổi hiệu quả toàn bộ chuỗi thành giá trị số nguyên dựa trên số ban đầu. Phần còn lại của chuỗi bị bỏ qua hoàn toàn. Do đó, 5 == "5 of something" trong thực tế được coi là 5 == 5.

Điều này thậm chí còn trở nên kỳ lạ khi so sánh một chuỗi với số nguyên 0:

0 == "Example string" // true

Bởi vì không có số, nghĩa là 0 chữ số trong chuỗi. PHP coi toàn bộ chuỗi này là số nguyên 0.

Chúng ta hãy xem xét ví dụ:

$login = unserialize($_COOKIE)
if ($login['password'] == $password) {
// log in successfully
}

Như chúng ta thấy ở đây có biến login được gán unserialize($_COOKIE) sau đó so sánh pass từ login nhưng ở đây chỉ so sánh == khi đó chúng ta có thể bypass dễ dàng (Nếu chúng ta đoán được dạng mật khẩu có trong database) và đặc biệt nó được deserialize nữa nên khi đó chúng ta có thể thay đổi kiểu dữ liệu.

Sử dụng chức năng ứng dụng (application functionality)

Cũng như chỉ đơn giản là kiểm tra các giá trị thuộc tính, chức năng của trang web cũng có thể thực hiện các thao tác nguy hiểm đối với dữ liệu từ một object được giải phóng. Trong trường hợp này, bạn có thể sử dụng tính năng deserialization không an toàn để truyền dữ liệu không mong muốn và tận dụng chức năng liên quan để gây thiệt hại.

Ví dụ: là một phần của chức năng "Xóa người dùng" của trang web, ảnh hồ sơ của người dùng sẽ bị xóa bằng cách truy cập vào đường dẫn tệp trong $user->image_locationthuộc tính. Nếu$userđược tạo từ một object được serialize, kẻ tấn công có thể khai thác điều này bằng cách chuyển một object đã sửa đổi với image_locationtập hợp vào một đường dẫn tệp tùy ý.

Magic methods

Magic methods là một tập hợp con đặc biệt của các method(phương thức) mà bạn không phải gọi một cách rõ ràng. Thay vào đó, chúng được gọi tự động bất cứ khi nào một sự kiện hoặc kịch bản cụ thể xảy ra. Các phương thức ma thuật là một đặc điểm chung của lập trình hướng đối tượng trong các ngôn ngữ khác nhau. Đôi khi chúng được biểu thị bằng tiền tố hoặc bao quanh tên phương thức bằng dấu gạch dưới kép.

Các nhà phát triển có thể thêm các magic method vào một lớp để xác định trước mã nào sẽ được thực thi khi sự kiện hoặc kịch bản tương ứng xảy ra. Chính xác khi nào và tại sao một phương pháp ma thuật được gọi là khác nhau giữa các phương pháp. Một trong những ví dụ phổ biến nhất trong PHP là __construct(), nó được gọi bất cứ khi nào một object của lớp được khởi tạo, tương tự như Python __init__. Thông thường, các magic method của phương thức khởi tạo như thế này chứa mã để khởi tạo các thuộc tính của cá thể. Tuy nhiên, các phương pháp ma thuật có thể được tùy chỉnh bởi các nhà phát triển để thực thi bất kỳ mã nào họ muốn.

Các phương pháp ma thuật được sử dụng rộng rãi và không tự nó thể hiện một lỗ hổng. Nhưng chúng có thể trở nên nguy hiểm khi mã mà chúng thực thi xử lý dữ liệu có thể kiểm soát được của kẻ tấn công, ví dụ, từ một object được deserialize. Điều này có thể bị kẻ tấn công khai thác để tự động gọi các phương thức trên dữ liệu được giải hóa khi các điều kiện tương ứng được đáp ứng.

Quan trọng nhất trong bối cảnh này, một số ngôn ngữ có các magic method được gọi tự động trong quá trình giải mã. Ví dụ, unserialize()phương thức của PHP tìm kiếm và gọi __wakeup() magic method của một object.

Trong Java deserialization, điều tương tự cũng áp dụng cho ObjectInputStream.readObject()phương thức, được sử dụng để đọc dữ liệu từ luồng byte ban đầu và về cơ bản hoạt động giống như một phương thức khởi tạo để "reinitializing - khởi tạo lại" một object được serialize. Tuy nhiên, Serializablecác lớp cũng có thể khai báo readObject()phương thức riêng của chúng như sau:

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
    // implementation
}

Method readObject() được khai báo theo cách chính xác này hoạt động như một phương thức ma thuật được gọi trong quá trình deserialization. Điều này cho phép lớp kiểm soát chặt chẽ hơn việc deserialization các trường của chính nó.

Inject các object tùy ý

Như chúng ta đã thấy, đôi khi có thể khai thác insecure deserialization bằng cách chỉ cần chỉnh sửa object do trang web cung cấp. Tuy nhiên, việc inject các loại object tùy ý có thể mở ra nhiều khả năng hơn.

Trong lập trình hướng đối tượng, các phương thức có sẵn cho một đối tượng(object) được xác định bởi lớp của nó. Do đó, nếu kẻ tấn công có thể thao túng lớp đối tượng nào đang được chuyển vào dưới dạng dữ liệu tuần tự hóa, chúng có thể ảnh hưởng đến mã nào được thực thi sau đó và thậm chí trong quá trình giải mã hóa.

Các phương pháp giải mã hóa thường không kiểm tra những gì chúng đang giải mã hóa. Điều này có nghĩa là bạn có thể chuyển các đối tượng của bất kỳ lớp có thể serialize có sẵn vào trang web và đối tượng sẽ được deserialize. Điều này cho phép kẻ tấn công tạo các thể hiện của các lớp tùy ý một cách hiệu quả. Thực tế là đối tượng này không thuộc lớp mong đợi không quan trọng. Loại đối tượng không mong muốn có thể gây ra một ngoại lệ trong logic ứng dụng, nhưng đối tượng độc hại sẽ được khởi tạo trước đó.

Nếu kẻ tấn công có quyền truy cập vào source code, chúng có thể nghiên cứu chi tiết tất cả các lớp có sẵn. Để xây dựng một cách khai thác đơn giản, họ sẽ tìm kiếm các lớp có chứa các phương thức ma thuật giải hóa, sau đó kiểm tra xem có bất kỳ lớp nào trong số chúng thực hiện các thao tác nguy hiểm trên dữ liệu có thể kiểm soát được hay không. Sau đó, kẻ tấn công có thể truyền vào một đối tượng được serialize của lớp này để sử dụng phương thức ma thuật của nó để khai thác.

Gadget chains

"Gadget" là một đoạn code tồn tại trong ứng dụng có thể giúp kẻ tấn công đạt được một mục tiêu cụ thể. Một gadget riêng lẻ có thể không trực tiếp làm bất cứ điều gì có hại với thông tin nhập của người dùng. Tuy nhiên, mục tiêu của kẻ tấn công có thể chỉ đơn giản là gọi một phương thức sẽ chuyển đầu vào của họ vào một thiết bị khác. Bằng cách xâu chuỗi nhiều gadget lại với nhau theo cách này, kẻ tấn công có thể chuyển đầu vào của chúng vào một "sink gadget" nguy hiểm, nơi nó có thể gây ra thiệt hại tối đa.

Điều quan trọng là phải hiểu rằng, không giống như một số kiểu khai thác khác, chuỗi gadget không phải là payload của các phương thức chuỗi do kẻ tấn công xây dựng. Tất cả các mã đã tồn tại trên trang web. Điều duy nhất mà kẻ tấn công kiểm soát là dữ liệu được chuyển vào chuỗi gadget. Điều này thường được thực hiện bằng cách sử dụng một phương pháp ma thuật hay còn gọi là magic method được gọi trong quá trình deserialization, đôi khi được gọi là "kick-off gadget".

Trong thực tế, nhiều lỗ hổng bảo mật không an toàn sẽ chỉ có thể bị khai thác thông qua việc sử dụng các gadget chain. Điều này đôi khi có thể là một chuỗi một hoặc hai bước đơn giản, nhưng việc xây dựng các cuộc tấn công có mức độ nghiêm trọng cao có thể sẽ yêu cầu một chuỗi các khởi tạo đối tượng và lệnh gọi phương thức phức tạp hơn. Do đó, có thể xây dựng các gadget chains là một trong những khía cạnh quan trọng của việc khai thác thành công quá trình bay không an toàn.

Nói chung, gadgetchain là kết quả của việc lắp ghép các method call, gán ghép các field làm sao cho nó đi theo luồng mà mình mong muốn: RCE, write file, …

Exploit cùng gadget chains có sẵn

Việc xác định gadget chains theo cách thủ công có thể là một quá trình khá gian nan và hầu như không thể thực hiện được nếu không có quyền truy cập source code. May mắn thay, có một số tùy chọn để làm việc với gadget chains được tạo sẵn mà bạn có thể thử trước.

Có một số tool có sẵn cung cấp một loạt các chuỗi được phát hiện trước đã được khai thác thành công trên các trang web khác. Ngay cả khi bạn không có quyền truy cập vào mã nguồn, bạn có thể sử dụng các công cụ này để xác định và khai thác các lỗ hổng giải mã không an toàn với tương đối ít nỗ lực. Cách tiếp cận này có thể thực hiện được do việc sử dụng rộng rãi các thư viện chứa các gadget chain có thể khai thác. Ví dụ: nếu một gadget chain trong thư viện Apache Commons Collections của Java có thể được khai thác trên một trang web, thì bất kỳ trang web nào khác triển khai thư viện này cũng có thể được khai thác bằng cách sử dụng cùng một chuỗi.(Bất kỳ trang web nào sử dụng thư viện này đều có thể dùng cùng một gadget chains và có thể thay đổi một xíu...)

ysoserial

ysoserial là một tập hợp các gadget và "gadget chains" lập trình hướng thuộc tính được phát hiện trong các thư viện java thông thường, trong các điều kiện thích hợp, có thể khai thác các ứng dụng Java thực hiện việc giải mã không an toàn cho các đối tượng. Chương trình trình điều khiển chính nhận một lệnh do người dùng chỉ định và bao bọc nó trong chuỗi tiện ích do người dùng chỉ định, sau đó tuần tự hóa các đối tượng này thành stdout. Khi một ứng dụng có các tiện ích cần thiết trên đường dẫn classpath giải mã dữ liệu này một cách không an toàn, chuỗi sẽ tự động được gọi và khiến lệnh được thực thi trên máy chủ ứng dụng.

Lưu ý rằng không phải tất cả các gadget chains trong ysoserial đều cho phép bạn chạy mã tùy ý. Thay vào đó, chúng có thể hữu ích cho các mục đích khác. Ví dụ: bạn có thể sử dụng những cách sau để giúp bạn nhanh chóng phát hiện insecure deserialization trên hầu như bất kỳ máy chủ nào:

  • Chuỗi URLDNS kích hoạt tra cứu DNS cho một URL được cung cấp. Quan trọng nhất, nó không dựa vào ứng dụng đích sử dụng một thư viện dễ bị tấn công cụ thể và hoạt động trong bất kỳ phiên bản Java nào đã biết. Điều này làm cho nó trở thành gadget chains phổ biến nhất cho các mục đích phát hiện. Nếu bạn phát hiện một đối tượng được serialization trong lưu lượng truy cập, bạn có thể thử sử dụng gadget chain này để tạo một đối tượng kích hoạt tương tác DNS với máy chủ Burp Collaborator. Nếu có, bạn có thể chắc chắn rằng quá trình deserialization đã xảy ra trên mục tiêu của bạn.

  • JRMPClient là một chain phổ biến khác mà bạn có thể sử dụng để phát hiện ban đầu. Nó khiến máy chủ thử thiết lập kết nối TCP với địa chỉ IP được cung cấp. Lưu ý rằng bạn cần cung cấp địa chỉ IP thô thay vì tên máy chủ. Chain này có thể hữu ích trong môi trường mà tất cả lưu lượng ra ngoài đều được tường lửa, bao gồm cả tra cứu DNS. Bạn có thể thử tạo tải trọng bằng hai địa chỉ IP khác nhau: địa chỉ cục bộ và địa chỉ bên ngoài có tường lửa. Nếu ứng dụng phản hồi ngay lập tức cho một payload có địa chỉ cục bộ, nhưng lại treo đối với một tải trọng có địa chỉ bên ngoài, gây ra sự chậm trễ trong phản hồi, điều này cho thấy rằng gadget chain đã hoạt động vì máy chủ đã cố gắng kết nối với địa chỉ có tường lửa. Trong trường hợp này, sự khác biệt nhỏ về thời gian trong các phản hồi có thể giúp bạn phát hiện xem quá trình deserialization có xảy ra trên máy chủ hay không, ngay cả trong trường hợp blind.

PHP Generic Gadget Chains

Hầu hết các ngôn ngữ thường gặp phải lỗ hổng insucure deserialization đều có các tool có các payload phổ biến. Ví dụ: đối với các trang web dựa trên PHP, bạn có thể sử dụng "PHP Generic Gadget Chains" (PHPGGC).

Sử dụng các gadget chain đã được ghi lại (Các gadget chain đã được khai thác trước đó)

Có thể không phải lúc nào cũng có sẵn một công cụ chuyên dụng để khai thác các gadget chain đã biết trong khuôn khổ được ứng dụng đích sử dụng. Trong trường hợp này, chúng ta có thể tìm kiếm trực tuyến để xem liệu có bất kỳ khai thác được ghi lại nào mà chúng ta có thể điều chỉnh theo cách thủ công hay không. Việc tinh chỉnh code có thể yêu cầu một số hiểu biết cơ bản về ngôn ngữ và các hoạt động của nó, và đôi khi bạn có thể cần serialize object.

Tự tạo script riêng

PHAR deserialization

Last updated