CS分为controller,teamserver,beacon三端

环境

孟师傅的反编译过程

  1. 新建CS、cs_bin、cs_src目录
  2. 从IDEA的安装目录找到java-decompiler.jar,复制到CS目录下,java-decompiler.jar所在路径为idea2020\plugins\java-decompiler\lib
  3. 把需要反编译的CS Jar包复制到cs_bin目录下

image.png

  1. 命令

    1. java -cp .\java-decompiler.jar org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler -dgs=true .\cs_bin\cobaltstrike.jar .\cs_src\

    image.png

  2. 在cs_src目录下则会生成反编译后的jar包,对比反编译前后的jar包,可发现.class文件已经被反编译为.java文件

image.png
image.png

  1. IDEA新建一个Project,decompiler放反编译后cs jar解压缩后的文件,lib目录放反编译前的cs jar包

image.png

cobaltstrike分析-第一部分 - 图6
cobaltstrike分析-第一部分 - 图7

  1. 添加模块依赖(lib下的jar包)

image.png
image.png

  1. 需要改动的文件copy到src对应目录下

image.png
image.png

密码校验

image.png

启动TeamServer后,首先会创建SecureServerSocket对象,然后循环调用acceptAndAuthenticate()接受认证信息

SHA256 hash of SSL cert is 是启动teamserver的特征,可以根据这个进行全局搜索

其中SecureServerSocket var4 = new SecureServerSocket(var3, this.port);
这行是TCP TLS监听的代码,Var3是程序监听的IP地址,如果在启动teamserver时候没有指定默认监听绑定的地址就是0.0.0.0

acceptAndAuthenticate方法是验证信息的作用
image.png
最终会调用SecureServerSocket.this.authenticate方法,第一个参数是连接的socket对象,第二个参数是当前服务端设置的连接密码,第三个参数是客户端的IP地址

验证成功后,执行clientAuthenticated方法来线程执行ManageUser以处理与Controller的信息


当用户点击Connect按钮的时候
客户端首先在dialogAction()方法获得相应的登录信息
image.png
然后传入host,prot创建的安全套接字
image.png

在socureSocket的构造方法中设置了相关的socket属性,调用createSocket()传入要连接的ip地址和port
image.png

客户端调用完createSocket()后,teamserver端acceptAndAuthenticate()会接收到信息,其中跟入authenticate(Socket var1, String var2, String var3) 方法处理接收到的信息

image.png

跟进此方法,当var4没有读取到足够的字符的时候就一直阻塞,直到用户将信息发完
从socket请求中读取4字节int型变量,如果读取到的数据与48879相等,则会进行后面的处理过程,否则返回false,身份认证失败,关闭客户端连接

48879可以改成其他的值,可以防止teamserver口令爆破,和未正常人员登录(防溯源,48879不只是这一处,客户端也有一段登录请求包的构造过程[ssl/Secureket/authenticate])

客户端构造完securesocket对象后,调用其authenticate方法,并传入登录密码,该方法主要通过密码构造相应的数据包,其数据包先传入48879这个数值(标志),然后再传入密码长度,接着传入密码内容,最后以0x41进行填充
image.png
image.png

当var3.flush()调用向server端发送数据,teamserver的authenticate(Socket var1, String var2, String var3)方法就停止阻塞,teamserver就开始验证了,判断标志位是否正确,读取密码,读取填充字符

image.png

若密码相等则发送51966标志数给客户端

image.png
然后返回执行PostAuthentication对象实现的clientAuthenticated();
image.png
image.png
新建线程,等待后续接受客户端所发送的信息
image.png

在Controller这边同样也会进行验证
image.png

51966也算一个特征值

至此teamserver端校验客户端密码完毕


aggressor.authenticate消息类型传输

接着客户端再通过SecureSocket对象构造出TeamSocket对象
image.png
image.png
传入Teamsocket对象创建teamqueue对象,其中teamreader与teamwriter均为teamqueue的内部类,均实现runnable接口负责与teamserver通信
image.png
image.png
然后调用teamqueue的call()方法,把消息类型aggressor.authenticate,用户名,密码,版本信息均传入,再把请求通过TeamWriter属性发送给teamserver端:

在调用call中,最关键的就是addRequest,它将构造好的Request对象存放到LinkedList当中 因为此时专门有一个线程TeamWriter一直在从LinkedList中取值发送,所以在添加完之后,这个信息就会被发送到TeamServer中

image.png

image.png
image.png

image.png

TeamServer端收到客户端的aggressor.authenticate类型请求包

image.png

跟进process(),先比较数据包的类型,再判断版本号,接着校验密码和是否重复登录,最后向客户端回复success
image.png

最后新建名为write for nickname线程向各个客户端回复消息
image.png

客户端收到success回复
image.png

teamserver会创建Socket,并创建ManageUser来处理客户端发送的信息
image.png

客户端创建TeamQueue类来进行后续操作,TeamQueue是客户端用来处理与Teamserver通讯的
image.png

在TeamQueue的构造函数中,创建了两个线程分别来跑TeamQueue的内部类TeamReader和TeamWriter,用来与Teamserver通信
image.png

在TeamServer中,是由ManageUser一直循环等待客户端发送到请求的,在上面发送完成后,TeamServer也就收到请求了
image.png
进入到process来处理请求,通过对比任务类型,来决定实际执行的内容

image.png
接着对版本,密码进行校验
image.png
全部成功后返回success

接着会起一个线程,ManageUser的内部类BroadcastWriter
image.png

此时客户端由teamReader接收到信息
image.png
这里接受的是Reply,发送的时候是Request,这两个类基本是一样的,可能是用来区别数据包的

在请求的时候填入的callback,也是在这个时候使用的,在之前call的时候,将一个callback值与这个对象做Map
在这个时候取出来用于去调用对应类的result方法
image.png

在判断返回值是SUCCESS之后,接着又发送了aggressor.metadata
image.png

aggressor. metadata消息类型传输

调用call与之前一样,此时传入的参数是当前的时间戳
image.png

Aggressor端继续向teamserver端发送:aggressor.metadata类型请求:

image.png

TeamServer中的ManageUser接到消息后,继续走process处理

image.png
继续跟入process(),该函数主要用hashmap存放相关的数据,最后向aggressor客户端返回了aggressor.matedata类型和hashmap数据:
image.png
image.png
aggressor客户端接收teamserver端返回的aggressor.matedata类型和hashmap数据:

image.png
跟入processread()函数,函数主要获取消息包中数据类型和数据:

image.png
再跟入result(),可见该函数负责处理从teamserver端返回的aggressor.authenticate和aggressor.metadata类型的信息:
image.png
传入metadata数据hashmap var2来构造AggressorClient对象,跟入该对象的构造方法:
image.png
继续跟如setup()方法,该方法主要是注册各类Bridge对象,储存teamserver端返回的metadata,加载插件框,以及发送aggressor.ready给teamserver告知其准备完。
image.png
最后调用该对象的showTime(),至此显示出主界面,后续同步相关数据:
image.png

小结

至此,我们知道了cs的agressor端登录teamserver端通讯方式,所以可以进行相应简单的修改来规避cs登录爆破:
1、 teamserver端避免使用默认的端口号50050。
2、 如果修改48879这个标识数,需要修改的地方有三个,涉及到修改aggressor端:

SecureSocket的authenticate方法 AsymmetricCrypto的decrypt()方法 SecureServerSocket的authenticate方法

image.png

数据同步

在register中,会先将user与对应的manageUser存储到Map当中,接着调用playback来处理同步工作
image.png
在playback会计算this.transcripts与this.replayme的总大小,然后进行发送
image.png
send的时候,就会用到了前面所创建的Map,通过名字取出相应的ManagerUser
image.png

之后也就是发送的常规流程,将信息打包成Reply或Request然后发送
image.png
客户端会在TeamReader中接到信息,因为callback是0,所以会走else当中处理,调用DataManager的result方法来进行处理
image.png

跟进result,发现用于判断sent和total是否相等,来明确是否已经完成
image.png
接着遍历并调用对应的result方法
image.png
继续回到 TeamServer ,接下来当前线程会来遍历 this.transcripts 和 this.replayme,并将信息 send 到 Controller,由于这里 this.transcripts 为空,就直接看 this.replayme
image.png
先把其中所对应的值都取出来,修改了当前的 message 信息以后,先将 playback.status 包发回,然后再将取出来的 Key、Value 发回,最后将 send 加一,用于 Controller 中对比 send 与 total 值
image.png
当回信息时,客户端 判断是 Data,所以进入了另外的分支,由于不是 ChangeLog 类型的内容,存储到 Map 后就直接结束了

image.png
之后再调用 将当前用户信息提供给客户端
image.png

在TeamServer继续执行调用的时候,也是调用的broadcast来同步eventlog
image.png
之后也就进入到了常态化,接客户端的aggressor.ping,和BroadcastWriter回写Beacons信息
image.png

流程图

未命名文件.png