开始
域前置已经不是一个新鲜的话题。通信流程如下:
而其中最为关键的地方在于在client中使用自定义的Host字段。在CobaltStrike的相关页面中可以看到相关的配置方法。 https://www.cobaltstrike.com/help-http-beacon
在cs4.0后可以直接在新建监听器时直接指定HTTP Host Header。而在此之前想要指定client的host只能通过修改profile后进行重载。而这两种方式的优先级又是怎样?今天通过简单的逆向对这个疑惑进行了验证。
验证
直接拿到CS.jar进行解压,然后在idea中打开即可看到反编译出的代码,其中关键部分如下:(beacon\BeaconPayload.class)
String var17 = this.listener.getHostHeader();
if (var17 != null && var17.length() != 0) {
if (Profile.usesHostBeacon(this.c2profile)) {
var16.addString(54, "", 128);
CommonUtils.print_stat("Now `althost` is not null,but will use profile");
} else {
var16.addString(54, "Host: " + this.listener.getHostHeader() + "\r\n", 128);
CommonUtils.print_stat("Now `althost` is not null, will use althost, this value is "+this.listener.getHostHeader());
}
} else {
CommonUtils.print_stat("Now `althost` is null, will find `Host` in profile.(If specified)");
var16.addString(54, "", 128);
}
public String getHostHeader() {
return DialogUtils.string(this.options, "althost");
}
public static boolean usesHostBeacon(Profile paramProfile) {
return (paramProfile.usesHost(".http-get.client.metadata") || paramProfile.usesHost(".http-post.client.id") || paramProfile.usesHost(".http-post.client.output"));
}
public boolean usesHost(String paramString) {
Program program = getProgram(paramString);
return (program != null && program.usesHost());
}
public Program getProgram(String paramString) {
return (Program)this.data.get(paramString);
}
public boolean program.usesHost() {
return this.host;
}
(为了方便理解,我做了一些修改与注释)
通过代码的阅读,我们可以看出,this.listener.getHostHeader() 是获取监听器中HTTP Host Header的方法。但是只有在 this.listener.getHostHeader()的结果不为空与Profile.usesHostBeacon(this.c2profile)的值不为真的情况下才会使用this.listener.getHostHeader() 的值。而 Profile.usesHostBeacon(this.c2profile) 的值取决于profile文件中,http-post.client.id、.http-post.client.output、.http-get.client.metadata中是否包含有host字段的相关操作(相关判断代码位于c2profile\Loader.class中 public int parse方法内,通过此方法最终使program.usesHost() 返回为True)。
http-post {
set uri "/c/msdownload/update/others/2016/12/3215234_";
set verb "GET";
client {
header "Accept" "*/*";
#session ID
id {
prepend "download.windowsupdate.com/c/";
header "Host"; ## 此处作为关键判断
}
#Beacon's responses
output {
base64url;
append ".cab";
uri-append;
}
}
server {
header "Content-Type" "application/vnd.ms-cab-compressed";
header "Server" "Microsoft-IIS/8.5";
header "MSRegion" "N. America";
header "Connection" "keep-alive";
header "X-Powered-By" "ASP.NET";
#empty
output {
print;
}
}
}
效果如下:
所以host字段的选取流程如下:
加载profile文件,将profile中的http header相关配置加载到变量中。此时如果有http-get \ http-post 下的client 中含有
header "Host" "www.baidu.com"
的话,通信过程中的host字段设置为此。判断监听器中是否有指定了http host header字段
如果上步为真,进一步判断profile文件中http-post.client.id、.http-post.client.output、.http-get.client.metadata中是否包含有host字段
如果上步为真,则不改变加载profile中的相关配置【准确来说是添加一个空值,即var16.addString(54, “”, 128);】。
如果为假 设定host字段为监听器中指定的http host header字段【var16.addString(54, “Host: " + this.listener.getHostHeader() + “\r\n”, 128);】,覆盖掉第一步中的Host配置。
另外一个值得注意的点。现在可以通过固定的算法进行未授权下载stage后并解密,其中有一项配置为 host 。如果单纯只使用profile文件来指定host的话,该配置项解密出的结果为空。
回编译
将需要修改的文件保存为 xxx.java ,xxx表示原始的文件名,该文件名不要做改动。然后使用javac进行编译时指定cs原始包作为依赖即可:
"C:\Program Files\Java\jdk1.7.0_80\bin\javac.exe" -cp .\cobaltstrike.jar ".\ServerUtils.java"
编译完成后得到.\ServerUtils.class,可以直接把cs.jar当作压缩包打开进行覆盖。