从PHP内核层面防范PHP WebShell
[目录]
1. 简述
2. php的执行流程
3. php的生命周期
4. php源代码分析以及功能性代码的实现
5. 总结
6. 参考资料
一、简述
依据php特定运行环境、php某些特定函数缺陷、php普通函数可以实现变化多端的php
webshell,php版本的scanwebshell也不是太给力。php webshell功能最大化就是实现文件、
目录、命令、数据库等操作,这些都是基于php代码实现的。把相关功能化的php函数运行参
数提取出来,然后做一个判断,这样就能从本质上防范php webshell,在php这个层面实现
其安全的最大化。这里介绍下通过编写php扩展来实现这个思路,当然需要的话也可以重新
编译php源代码来实现。
首先我们了解下php的执行流程、php生命周期,接下来通过分析具体函数的php源代码
来实现功能性代码。
二、php的执行流程
2.1 scanner
将PHP代码转换为Tokens,详见代码Zend/zend_language_scanner.l。
2.2 parser
将Tokens转换成表达式,详见代码Zend/zend_language_parser.y。
2.3 compile
将表达式编译成opcode。opcode存放在op_array中。
2.4 execute
Zend Engine调用zend_execute来执行op_array,输出结果。
三、php的生命周期
3.1 STARTUP
1、初始化引擎和核心组件。
2、解析php.ini。
3、初始化静态构建的模块(MINIT)。
4、初始化共享模块(MINIT)。
3.2 ACTIVATION
1、初始化环境变量、变量。
2、激活静态构建的模块(RINIT) 。
3、激活共享模块(RINIT) 。
3.3 RUNTIME
1、编译和执行php.ini中auto_prepend_file选项指定的文件。
2、编译和执行所请求的文件。
3、编译和执行php.ini中auto_append_file选项指定的文件。
3.4 DEACTIVATION
1、调用用户指定的退出函数。
2、销毁对象实例。
3、停用模块(RSHUTDOWN)。
4、清空输出。
5、清理环境。
6、释放剩余的非持久内存。
3.5 SHUTDOWN
1、关闭启动的全部模块(MSHUTDOWN)。
2、关闭引擎。
四、php源代码分析以及功能性代码的实现
php函数分为两种:一种是Zend的函数,这类函数数量比较少,比如eval函数。第二种
是由PHP_FUNCTION宏编写的,这类函数数量比较多,比如system函数。实现对两类函数在提
取运行时的参数的方式也不相同,比如处理eval函数用重写zend_compile_string的方式,
而处理system函数则对HashTable操作。下边就以eval函数和system函数为例进行分析、代
码实现。
4.1 eval函数代码分析与代码实现
首先我们看php源代码中eval函数是如何实现的,部分代码如下:
// PHPSRC/Zend/zend_vm_def.h
if (inc_filename->type!=IS_STRING) {
tmp_inc_filename = *inc_filename;
zval_copy_ctor(&tmp_inc_filename);
convert_to_string(&tmp_inc_filename);
inc_filename = &tmp_inc_filename;
}
case ZEND_EVAL: {
/* 调用zend_make_compiled_string_deion函数 */
char *eval_desc = zend_make_compiled_string_deion("eval()"d code" TSRMLS_CC);
/* 调用zend_compile_string函数 */
new_op_array = zend_compile_string(inc_filename, eval_desc TSRMLS_CC);
efree(eval_desc);
}
/* 执行op_array */
zend_execute(new_op_array TSRMLS_CC);
//PHPSRC/Zend/zend.c
#define COMPILED_STRING_DEION_FORMAT "%s(%d) : %s"
ZEND_API char *zend_make_compiled_string_deion(char *name TSRMLS_DC)
{
zend_spprintf(&compiled_string_deion, 0, COMPILED_STRING_DEION_FORMAT, cur_filename, cur_lineno, name);
return compiled_string_deion; //返回值包含"eval()"d code"字符串
}
//PHPSRC/Zend/zend_compile.c
ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, char *filename TSRMLS_DC);
新文章:
- CentOS7下图形配置网络的方法
- CentOS 7如何添加删除用户
- 如何解决centos7双系统后丢失windows启动项
- CentOS单网卡如何批量添加不同IP段
- CentOS下iconv命令的介绍
- Centos7 SSH密钥登陆及密码密钥双重验证详解
- CentOS 7.1添加删除用户的方法
- CentOS查找/扫描局域网打印机IP讲解
- CentOS7使用hostapd实现无AP模式的详解
- su命令不能切换root的解决方法
- 解决VMware下CentOS7网络重启出错
- 解决Centos7双系统后丢失windows启动项
- CentOS下如何避免文件覆盖
- CentOS7和CentOS6系统有什么不同呢
- Centos 6.6默认iptable规则详解