后门加密通信分析:HITCTF 2020 Godzilla

通信,至少两个实体才有通信这一说,通信各方都需要实现共同的一套通信逻辑,而这个通信逻辑就是我们要分析的,这个逻辑可能是软件实现,也可能是硬件实现。所以柿子要挑软的捏,找到通信各方里,最好分析的实体,一般来说肯定是软件了。Godzilla这款后门管理软件虽然没有开源,但是他的对等实体,也就是他自己的php后门,肯定是可以随便看以及调试的,也就是说并不需要知道他通信加密的所有细节,直接用后门php脚本里的函数就一定可以对发往该脚本的流量进行解密了。如果是对称加密的话,双向的流量也都可解。

本地分析

在第一个HTTP包中就能看到:

POST /backdoor.php HTTP/1.1
tools: Godzilla
User-Agent: Java/1.8.0_201

判断是Godzilla的后门流量,工具介绍以及下载地址如下:

分析文章:

所以首先本地分析一下,分析方法和巧用Zeek在流量层狩猎哥斯拉Godzilla一致,只不过这篇文章是比赛之后才有的,写WP就省事了,直接看这个就行。基本方法就是本地生成后门php然后测试,生成时需要配置密码和秘钥,密码就是后门接收指令的参数名,秘钥就是负责加密通信的口令。分析php,发现密文是通过秘钥的md5进行加密传输的,并且payload的明文有明显的特征,会包含method字符串,提示key是5位的a-z,故爆破。

爆破密码

爆破脚本如下,暴力5个for循环:

<?php
    session_start();
    @set_time_limit(0);
	@error_reporting(0);
    function E($D,$K){
        for($i=0;$i<strlen($D);$i++) {
            $D[$i] = $D[$i]^$K[$i+1&15];
        }
        return $D;
    }
    function Q($D){
        return base64_encode($D);
    }
    function O($D){
        return base64_decode($D);
    }
    function boom($test,$message){
        $T=substr(md5($test),0,16);
        $F=O(E(O($message),$T));
        return $F;
    }

    for ($k1=ord("a");$k1 <= ord("z");$k1++) {
    for ($k2=ord("a");$k2 <= ord("z");$k2++) {
    for ($k3=ord("a");$k3 <= ord("z");$k3++) {
    for ($k4=ord("a");$k4 <= ord("z");$k4++) {
    for ($k5=ord("a");$k5 <= ord("z");$k5++) {
        $key = chr($k1).chr($k2).chr($k3).chr($k4).chr($k5);
        if(strstr(boom($key,'BjM1B1d+DAhjC35GbGRSDjZVOQFsfHBaZzcFDw==&5Ye66aKY5Lq66K077ya6KaB5LuU57uG5YiG5p6Q5rWB6YeP5ZOm77yB'),"method")){
            echo "[+]success ".$key."\n";
            exit(0);
        }
    }}}}}

结果:

[+]success toolx

后续的过程就是解密流量流量了

解密流量

  • 所有控制端发包的特征是:POST正文中的shell=字段,需要url解码,然后解密,解完之后还会有发现cmdLine字段,再base64解一遍就行
  • 所有控制端收包的特征是:在f1d和c53之间的密文数据(看出来的),不需要url解码,然后解密一遍即可
<?php
    session_start();
    @set_time_limit(0);
	@error_reporting(0);
    function E($D,$K){
        for($i=0;$i<strlen($D);$i++) {
            $D[$i] = $D[$i]^$K[$i+1&15];
        }
        return $D;
    }
    function Q($D){
        return base64_encode($D);
    }
    function O($D){
        return base64_decode($D);
    }
    function boom($test,$message){   
        $T=substr(md5($test),0,16);
        $F=O(E(O($message),$T));
        return $F;
    }
    function get_between($input, $start, $end) {
        $substr = substr($input, strlen($start)+strpos($input, $start),(strlen($input) - strpos($input, $end))*(-1));       
        return $substr; 
         
    }

    $f = fopen("./EasyFlow.pcapng", "r");
    if ($f) {
        while (($line = fgets($f, 1024)) !== false) {
            // send
            $payload = get_between($line,"shell=","&");
            $decode1 = boom('toolx',urldecode($payload));
            $decode2 = get_between($decode1,"cmdLine=","&");
            if(!empty($decode2)){
                echo base64_decode($decode2);
            }
            
            // recv
            $payload = get_between($line,"f1d","c35");
            $decode = boom('toolx',$payload);
            if(!empty($decode)){
                echo $decode."\n";
            }
        }
        fclose($f);
    }

解完两条关键信息如下:

This is a flag, but you need a key to decrypt it. The key is hidden in the executed command!!!!!!
U2FsdGVkX1/cQubv1ugeIT9QuGKl3DCqDuFAfAF12Dd+gftsycOcUaA5xzLE2R0FjaD61xIRcWpOL3nAJOWnlg==

keyH1T@ctf 

AES解密

然后至于这个加密为啥是AES,我也不知道,比赛的时候因为收包多做了一遍url解码,导致flag那句base64的加号给整没了,然后就用openssl所有加密方式爆破了一遍,结果发现aes256,能解出来半句flag,后来发现是url解码的锅。扔到网上在线解密应该可以直接就解出来,也可以使用openssl解密:

  echo "U2FsdGVkX1/cQubv1ugeIT9QuGKl3DCqDuFAfAF12Dd+gftsycOcUaA5xzLE2R0FjaD61xIRcWpOL3nAJOWnlg==" | openssl enc  -aes256 -d -base64 -k "H1T@ctf" -A -salt
HITCTF2020{9afa9f0d5be613c536147eeda8132f49}