– Tác giả:
Drupal security team
– CVE link:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-7600
– Dạng lỗi:
Remote Code Execution
– Sản phẩm dính đạn:
Drupal trước 7.58, 8.x trước 8.3.9, 8.4.x trước 8.4.6, và 8.5.x trước 8.5.1
– Tóm tắt lỗi:
Kẻ tấn công có thể gọi Drupal Form Api Ajax Request có chứa function call_user_func
tự do
– Cụ thể:
Trong bài phân tích này mình xài drupal 8.3.8
Sơ lược về Drupal API:
– Được giới thiệu từ drupal 7
– Dùng để Rendering structured data thành HTML markup.
– Còn được gọi là Renderable Arrays, có dạng key-value. Key sẽ bắt đầu bằng dấu #
Ví dụ với element file
:
Nhìn sơ qua thì cũng hiểu đại khái nó là gì rồi ha, tựa tựa tạo config giao diện trước vậy đó.
Trở lại với lỗi Drupalgeddon2, chúng ta tìm được các keys có sử dụng call_user_func
là #pre_render, #post_render, #access_callback, #submit, #lazy_builder, #validate
Trong bài này mình sẽ chọn #post_render
( ./core/lib/Drupal/Core/Render/Renderer.php
)
Ok vậy nhiệm vụ của chúng ta bây giờ là tìm được cái param nào mà user submit lên có render, có thể thay đổi được key, và nhận key #post_render, để gọi thằng nó ra.
Khi ta upload 1 file, function này sẽ call API để resize hình lại, bắt request trong burpsuite, ta thấy:
Trong request ta thấy chương trình có gửi 1 biến element_parents
theo phương thức GET
với giá trị là user_picture/widget/0
luồng xử lý này nằm trong function uploadAjaxCallback
ở ./core/modules/file/src/Element/ManagedFile.php
line 176 $form_parents
sẽ có giá trị là 1 array, var_dump
ra xem thử:
array(3) { [0]=> string(12) "user_picture" [1]=> string(6) "widget" [2]=> string(1) "0" }
nó sẽ lấy giá trị từ element_parents
, tách ra theo dấu /
thành array và gán vào $form_parents
line 179 gọi hàm getValue
từ class NestedArray
, vào đó xem:
(./core/lib/Drupal/Component/Utility/NestedArray.php
)
&$array
đưa vào function này là array của các element
mặc định khi submit, chèn thử vô code debug nè:
line 72, 73 check:
ý chính đoạn này là xài $parent
làm key path của array
$ref = &$ref[$parent]; lần đầu
=> $ref['user_picture']
$ref = &$ref[$parent]; lần 2
=> $ref['user_picture']['widget']
$ref = &$ref[$parent]; lần 3
=> $ref['user_picture']['widget'][0]
giả sử sửa giá trị của mail
khi upload:
account/mail/#value
là form element trỏ đến giá trị của mail
=> $ref[‘account’][‘mail’][#value]
$form sẽ trả về giá trị của biến mail nhập vào, debug:
sau đó thì $form sẽ được đưa vào function renderRoot
=> Render input ta control ^_^!
– Exploit:
Trở lại đoạn code ban đầu:
line 503 gọi hàm call_user_func
:
vậy sửa cái mail
cho phù hợp nữa thôi ^_^, PoC: