所有的授权实战入侵网站已添加“如何入侵”标签,在侧边栏的归档中选择“如何入侵”即可查看所有文章

MENU

SplDoublyLinkedList与绕过php禁用函数

November 3, 2022 • Read: 207 • 常山阅读设置

SplDoublyLinkedList与绕过php禁用函数2

之前写过一篇利用LD_PRELOAD实现绕过php禁用函数的文章,最近同事搞了一个宝塔的站,发现无法执行命令,通过Godzilla发现可以使用php7-sqldoublylinkedlist-uaf这个插件绕过禁用函数执行命令,于是本文主要就是来看看如何使用PHP中的SplDoublyLinkedList绕过禁用函数

首先来看看效果

首先,本文主要原理参考PHP SplDoublyLinkedList::offsetUnset sandbox escape

SplDoublyLinkedList

SplDoublyLinkedList提供了PHP(PHP>=5.3, PHP 7, PHP 8)中的双向链表功能。

Use After Free

SplDoublyLinkedList绕过PHP禁用函数是其实是利用UAF,这里就着重了解一下UAF的形成原理。

如果一个指针申请了指定大小的内存,使用结束后Free内存后并没有将该指针的指向地址为NULL,那么即使Free了内存,但依然可以对该地址的内存进行操作。如果其他程序操作了该内存,当下次指针再次使用该内存时就会出现问题。

所以在SplDoublyLinkedList的双向链表中,如果删除链表中的元素,SplDoublyLinkedList并不会立即清理相关的指针,这导致该链表指针会指向一个空地址,如果在这个空地址上构造恶意代码,那么正常使用SplDoublyLinkedList时,链表中的地址并没有释放,导致可以执行这个空地址上的恶意代码。

用简易代码演示一下:

#include<cstdio>
#include <cstdlib>
#include <cstring>
int main()
{    
    char* p1 = (char*)malloc(sizeof(char*)*10);//为p1申请一个10字节的地址
    memcpy(p1,"hello",10);//写入hello
    printf("p1 addr:%x,p1:%s\n",p1,p1);
    free(p1);  //释放p1
    char* p2 = (char*)malloc(sizeof(char*) * 10);//为p2申请一个10字节的地址
    memcpy(p2,"world",10);//写入world
    printf("p2 addr:%x p1:%s\n",p2,p2);
    printf("p1 addr:%x,p1:%s\n", p1, p1);
}

从图中可以看到p1释放内存后,p2申请了同样大小的内存,然后p2修改了内存后,p1和p2都显示同一内存地址以及同一字符。

如果在那个内存执行恶意代码,则会引起严重后果,代码如下:

#include<cstdio>
#include <cstdlib>
#include <cstring>

typedef void (*func_ptr)(char *);
void exp(char command[])
{
    system(command);
}

int main()
{    
    func_ptr *p1 = (func_ptr*)malloc(sizeof(int) * 10);//为p1申请一个10字节的地址
    memcpy(p1,"helloworld",10);//写入hello
    printf("p1 addr:%x,p1:%s\n",p1,p1);
    free(p1);  //释放p1
    func_ptr *p2 = (func_ptr*)malloc(sizeof(int) * 10);//为p2申请一个10字节的地址
    p2[3]=exp;
    p1[3]("/bin/sh");
}

可以看到通过UAF我们成功执行了/bin/sh命令

SplDoublyLinkedList绕过PHP禁用函数

具体使用方法请查阅https://github.com/cfreal/exploits/tree/master/php-SplDoublyLinkedList-offsetUnset,修改exploit.php153行中的id即可执行相应的命令。

Archives QR Code Tip
QR Code for this page
Tipping QR Code