Một vài note về Wordpress POP chain

Published By: RED TEAM

Published On: 30/06/2025

Published in:

Intro

Trong quá trình nghiên cứu về những lỗ hổng ở các component của Wordpress như là plugin thì mình thường tìm ra được lỗ hổng Insecure Deserialization do việc plugin sử dụng dữ liệu đầu vào của người dùng để có thể xử lí nhằm mục đích như là render hoặc là add options. Tuy nhiên ở thời điểm đó thì mình chỉ có thể chứng minh được rằng mình có thể gọi được bất kì class nào tùy ý chứ vẫn chưa có thể có được shell của server. Với lí do đó nên mình và một người em quen biết đã bắt đầu đi tìm POP chain ở trong Wordpress Core để có thể khai thác sâu hơn và nâng cao impact của lỗ hổng.

Tiến hành debug

Sau khi đã cài đặt Wordpress trên apache và những thứ liên quan như là Xdebug thì mình sẽ tạo một plugin như sau để có thể debug được POP Chain.

Ở đây mình có sử dụng thêm hàm wp_unslash vì lí do trong Wordpress core sẽ tự động gọi đến hàm wp_unslash nhằm mục đích tránh những lỗ hổng liên quan đến injection như là SQL Injection,... do đó mà payload chúng ta truyền vào sẽ bị Offset error trong quá trình deserialize payload.

Chính vì vậy mà để có thể thực hiện tấn công Insecure Deserialization thành công ở trên Wordpress thì ở control data cần phải có những hàm workaround như là wp_unslash, base64_decode, urldecode,stripslashes,... 

Ở đây mình sẽ bắt đầu đến với điểm đầu tiên của chain nằm ở class ParagonIE_Sodium_Core_Poly1305_State ở file wordpress/wp-includes/sodium_compat/src/Core/Poly1305/State.php.

Khi gọi đến magic function __destruct của class thì chúng ta thấy được nó sẽ bắt đầu lấy giá trị ở các offset theo giá trị tăng dần của biến $this->r. Ở đây mình set giá trị của $this->r là object của class WP_Block_List nên sẽ gọi đến function offsetGet của class WP_Block_List, cũng đồng thời vì lí do là class WP_Block_List đã implement class ArrayAccess.

Sau khi đi theo flow của chain thì chúng ta sẽ bắt đầu tạo một instance của class WP_Block.

Khi vào được hàm __construct của class WP_Block thì chúng ta sẽ thấy được class sẽ bắt đầu gọi đến function get_registered của bất kì class nào được khai báo ở trong biến $this->registry. Ở đây mình sẽ set giá trị của registry là object của class WP_Block_Patterns_Registry.

Ở hàm get_registered sẽ bắt đầu gọi đến hàm get_content của chính class WP_Block_Patterns_Registry

Đến với hàm get_content của class WP_Block_Patterns_Registry, chúng ta thấy được hệ thống sẽ bắt đầu gọi đến include với giá trị của $patterns[ $pattern_name ]['filePath'].

Đây chính là sink của POP chain vì ở đây chúng ta có thể sử dụng những cách tấn công từ LFI to RCE như là PHP filter chain, PHP session upload progess,... Ở đây để có thể quick demo thì mình sẽ sử dụng scheme data:// để có thể RCE 🥳.

Tuy nhiên nhược điểm của chain này là vì class ParagonIE_Sodium_Core_Poly1305_State không hề tồn tại trong quá trình chạy Wordpress core ở Linux instance nên chúng ta không thể gọi đến function offsetGet của class WP_Block_List được 😭. Chính vì vậy để khai thác được thì chúng ta còn phải xem thử sau khi plugin thực hiện unserialize object có tiến hành xử lí thêm như là access vào index của một property nào đó của object đó không.

Tham khảo

+ https://patchstack.com/academy/wordpress/vulnerabilities/php-object-injection/ 

+ https://vickieli.dev/insecure%20deserialization/pop-chains/

+ https://wpscan.com/blog/finding-a-rce-gadget-chain-in-wordpress-core/

28 lượt xem