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.php
153行中的id即可执行相应的命令。
《SplDoublyLinkedList与绕过php禁用函数》链接:https://xdym11235.com/archives/253.html
具体版权规定详见侧栏版权说明页面