冰蝎学习笔记

这篇文章记录冰蝎的学习,先大致了解一下原理,然后一点一点补充学习(其实原理什么的没有像学习之前感觉的那么难,但把所有的功能都实现,一点一点迭代,还是很强的。后面牛的是内存马那部分,再然后一步一步走到真正的无文件内存马)

冰蝎交互流程

冰蝎 v2.0.1 及之前使用的是动态密钥协商机制

冰蝎 v2.0.1 及之前使用的是动态密钥协商机制,使用POST发送payload之前一般会有两段包含16位字符串的明文报文。最后一个报文中的16位字符串为密钥。
简单画了一下交互图
冰蝎v2.0.1及之前

Behinder_v3.0 Beta 1 及之后使用的是预共享密钥

Behinder_v3.0 Beta 1 及之后使用的是预共享密钥,密钥为md5(“rebeyond”)[0:16],即e45e329feb5d925b。服务端直接硬编码进去,客户端根据用户设置的密码获取密钥md5(“rebeyond”)[0:16],所以如果要修改默认密钥就要手动修改马中的硬编码密钥。
进行全程无明文交互,waf比较难以防御。修改密钥之后,waf基本不可能通过解密进行拦截处理。
同时Behinder_v3.0 Beta 1 增强了内网穿透功能。
冰蝎v3.0Beta1及之后

为什么使用equals进行触发

这里为什么使用equals进行触发,具体原因可以参考https://xz.aliyun.com/t/2744#toc-7
简单来说就是:最开始通过重写Object类的toString方法来作为我们的Payload执行入口。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Payload {
@Override
public String toString() {
// TODO Auto-generated method stub
try {
Runtime.getRuntime().exec("calc.exe");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "OK";
}
}

这样的好处是我们可以取到Payload的返回值并输出到页面,但是缺点也很明显:在toString方法内部没办法访问Request、Response、Seesion等servlet相关对象。所以需要找一个带有入参的方法,并且能把Request、Response、Seesion等servlet相关对象传递进去。
为什么选择equals方法:重新翻看了一下Object类的方法列表,可以看到equals方法完美符合我们的要求:有入参,而且入参是Object类,在Java世界中,Object类是所有类的基类,所以我们可以传递任何类型的对象进去。

equals的参数设置:但是equals方法只接受一个参数,怎么把Request、Response、Seesion等servlet相关对象传进去。通过对servlet的9个对象分析发现,只要传递pageContext进去,便可以间接获取Request、Response、Seesion等对象,如HttpServletRequest request=(HttpServletRequest) pageContext.getRequest();

另外,如果想要顺利的在equals中调用Request、Response、Seesion这几个对象,还需要考虑一个问题,那就是ClassLoader的问题。JVM是通过ClassLoader+类路径来标识一个类的唯一性的。我们通过调用自定义ClassLoader来defineClass出来的类与Request、Response、Seesion这些类的ClassLoader不是同一个,所以在equals中访问这些类会出现java.lang.ClassNotFoundException异常。
解决方法就是复写ClassLoader的如下构造函数,传递一个指定的ClassLoader实例进去:

1
2
protected ClassLoader(ClassLoader parent)
Creates a new class loader using the specified parent class loader for delegation.

版本更新

同时Behinder_v3.0 Beta X 增加了很多模块,模块中的功能也不断在迭代,比如内网穿透、反弹shell、内存马等等

Behinder_v4.0 取消硬编码通信协议,传输协议完全自定义,并支持即时在线校验测试,这样就弥补了Behinder_v3.0中修改密钥很麻烦的问题。密钥支持xor、xor_base64(先base64解码,在与密钥xor)、aes、images、json(将所有信息层层封装成msg的值,每一层的value都用base64加密)

在《冰蝎v4.0传输协议详解》一文中作者提到:对于aes加解密方式,由于默认使用的是aes128的算法,会导致密文长度恒是16的整数倍,流量设备可能通过这个特征来对冰蝎做流量识别。
为了解决这个问题,可以自定义一个加解密函数,即在客户端生成密文后增加了一个魔法尾巴

1
2
3
4
5
6
7
8
9
10
11
12
13
//省略之前生成密文encrypted的代码
//增加魔法尾巴
int magicNum=Integer.parseInt(key.substring(0,2),16)%16;
java.util.Random random=new java.util.Random();
byte[] buf=new byte[magicNum];
for (int i=0;i<buf.length;i++)
{
buf[i]=(byte)random.nextInt(256);
}
java.io.ByteArrayOutputStream output = new java.io.ByteArrayOutputStream();
output.write(encrypted);
output.write(buf);
return output.toByteArray();

这里能根据密钥判断出魔法尾巴的长度。在解密的时候直接截去魔法尾巴,然后在解密就可以了。这样就避免由于密文长度而被识别出来的问题了。

1
2
3
4
String k="e45e329feb5d925b";
int magicNum=Integer.parseInt(k.substring(0,2),16)%16; //取magic tail长度
data=java.util.Arrays.copyOfRange(data,0,data.length-magicNum); //截掉magic tail
//省略解密操作

同时Behinder_v4.0新增支持Java Agent无文件落地注入内存马;新增平行世界模块,可对目标内网资产进行管理;新增主机扫描、端口扫描、服务识别等模块

内存马

冰蝎v3.0 注入内存马流程

使用的是self attach技术。入口点是net.rebeyond.behinder.ui.controller.MainController#injectMemShell

net.rebeyond.behinder.ui.controller.MainController#injectMemShell中,osType代表操作系统类型,用于获取对应的agent jar,所有的jar包保存在net/rebeyond/behinder/resource/tools中。

  • shellService.uploadFile()方法:
    通过Utils.getResourceData方法获取对于agent jar的字节码,然后通过shellService.uploadFile方法上传至受害端(对于Linux是/tmp/六位随机字符

  • shellService.loadJar()方法:
    loadJar()方法将net.rebeyond.behinder.payload.java.Loader传到受害端
    Loader实现的功能是通过URLClassLoader将上传的jar包加载到内存中。
    受害端实例化Loader后会执行Loader.equals方法,执行Loader逻辑。

    loadJar的意义是确保injectMemshell()loadAgent到/tmp/下的jar包?)

  • shellService.injectMemshell()方法:
    injectMemshell()方法将net.rebeyond.behinder.payload.java.MemShell传到受害端
    MemShell.equals方法首先设置了allowAttachSelf并调用了doAgentShell写入内存马。
    设置allowAttachSelf的原因时 rebeyond师傅在Java内存攻击技术漫谈中讲过,在JDK9以上,jdk.attach.allowAttachSelf默认为false,也就是无法Attach,所以才需要设置为true。
    调用doAgentShell,反射获取attachloadAgent方法并执行
    attach的是自身PID,因为这是将MemShell文件传到受害端,受害端执行的equals方法
    loadAgent的是/tmp/xxxxxx目录下的jar
    doAgentShell注入到受害端执行,相当于AttachAgentagentmaintransformjar包中,相当于AgentMainMyTransformer
    如果是linux则删除生成的临时文件,最后删除上传的jar包。

image-20230405004848011

下图是冰蝎自带windowslinux类型的agent jar包的一点区别

Snipaste_2023-04-05_10-38-51

Reference

项目地址https://github.com/rebeyond/Behinder
版本更新信息https://github.com/rebeyond/Behinder/releases
学习文章:
利用动态二进制加密实现新型一句话木马之客户端篇
利用动态二进制加密实现新型一句话木马之Java篇
冰蝎v2.0.1核心部分源码浅析
冰蝎v3.0操作使用手册
Java内存攻击技术漫谈
冰蝎v4.0传输协议详解
论如何优雅的注入Java Agent内存马