1. 极安网首页
  2. 网络安全技术

PHP SplDoublyLinkedList 用后释放漏洞分析

PHP SplDoublyLinkedList 用后释放漏洞分析-极安网

漏洞描述

PHP的SplDoublyLinkedList双向链表库中存在一个用后释放漏洞,该漏洞将允许攻击者通过运行PHP代码来转义disable_functions限制函数。在该漏洞的帮助下,远程攻击者将能够实现PHP沙箱逃逸,并执行任意代码。更准确地来说,成功利用该漏洞后,攻击者将能够绕过PHP的某些限制,例如disable_functions和safe_mode等等。

受影响版本

PHP v8.0(Alpha);
PHP v7.4.10及其之前版本;

厂商回应

根据我们的安全分类,我们认为这并非一个安全问题,因为它需要在服务器端执行非常特殊的代码才能够触发该漏洞。如果攻击者能够实现代码注入,那么肯定是由一个比该漏洞更加严重的漏洞存在所导致的。

漏洞演示

PHP SplDoublyLinkedList 用后释放漏洞分析-极安网

漏洞分析

SplDoublyLinkedList是PHP中的一个双向链表库(DLL),这个库支持进行迭代,即能够存储一个指针指向当前的DLL元素以实现迭代。这样一来,开发人员就可以通过调用next()和prev()来让DLL指向其他的元素了。

当我们删除DLL中的某个元素之后,PHP将从DLL中移除该元素,然后销毁掉zval,如果指针指向该元素的话,那么就存在空指针问题了。因此,当zval被销毁之后,当前指针仍然指向相关联元素,即使其已经被从链表中移除了。这样一来,用后释放问题便出现了,因为我们可以通过在zval的构造器中调用$dll->next()或$dll->prev()来触发该漏洞。

利用输入参数触发漏洞

我们可以使用两个值来创建一个SplDoublyLinkedList对象$s,第一个值是一个带有特殊结构体__destruct 的对象,另一个值我们不用理会。接下来,我们可以调用$s->rewind()来让当前迭代元素的指针指向我们的对象。当我们调用$s->offsetUnset(0)时,它将会调用底层C函数SPL_METHOD(SplDoublyLinkedList, offsetUnset)(该函数存在于ext/spl/spl_dllist.c中),这个函数将完成以下几件事情:

1、通过设置下列参数将元素从双线链表中移除:

element->prev->next = element->next

element->next->prev = element->prev

2、销毁相关的zval(llist->dtor);

3、如果intern->traverse_pointer指向目标元素,它会将指针设置为NULL;

在第二步中,会调用我们对象的__destruct方法,而intern->traverse_pointer仍然会指向该元素。为了触发用后释放问题,我们需要做下列几件事情:

通过调用$s->offsetUnset(0)来移除双向链表中的第二个元素,让intern->traverse_pointer->next指向一个未分配的空间;

调用$s->next():调用链为intern->traverse_pointer = intern->traverse_pointer->next。由于该地址已在第一步被释放,那么traverse_pointer将指向一个未分配的地址;

使用$s->current(),我们将能够访问未分配的地址,从而触发用后释放漏洞;

漏洞修复

需要在销毁zval之前清理掉intern->traverse_pointer指针,随后删除相关的引用。参考代码如下:

  1. was_traverse_pointer = 0;
  2. // Clear the current pointer
  3. if (intern->traverse_pointer == element) {
  4. intern->traverse_pointer = NULL;
  5. was_traverse_pointer = 1;
  6. }
  7. if(llist->dtor) {
  8. llist->dtor(element);
  9. }
  10. if(was_traverse_pointer) {
  11. SPL_LLIST_DELREF(element);
  12. }
  13. // In the current implementation, this part is useless, because
  14. // llist->dtor will UNDEF the zval before
  15. zval_ptr_dtor(&element->data);
  16. ZVAL_UNDEF(&element->data);
  17. SPL_LLIST_DELREF(element);

本文转载:Freebuf,不代表 极安网 立场,转载请注明出处:https://secvery.com/2523.html