從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規則詳解