In the last post I solved the the preliminary task and task 2, which are relatively easy compared to these. Let's jump into it.

Task 1

In this task, we are given the the two binaries we were in Task 2, of the last post, the pcap file, and a ransom note describing how to pay the ransomeware. It asks for

  • Victim Identifer
  • Encrypted Ransom Key
  • One-Time Passcord (OTP) used to authenticate the client to the ransomware
  • Escrow contract address

Now, according to the task, the victim computer, after being freshly infected, connects, sends out the victim identifier, an encrypted copy of the key, and a one time pass code (OTP).

The Escrow contract address and the victim identification are both in the ransom note in the following lines -

To receive the decryption key for your files:

make a transaction to the payRansom(...) function of the Escrow contract at address: 0x20a2bF3638A4354EF6DAa27FC7EEFf6C22722fB0

and

include your unique identification value: 0x65fdeac2e0d541dc499a669ab563ee7cb6bfa815f4eba4ccd2261a654f856a07

So, the Escrow contact address is

0x20a2bF3638A4354EF6DAa27FC7EEFf6C22722fB0

and the victim identifier

65fdeac2e0d541dc499a669ab563ee7cb6bfa815f4eba4ccd2261a654f856a07

We have to dive quite a bit deeper to acquire the encrypted key and the OTP.

In the pcap file there are 5 packets that transfer data, the first being the largest with 656 bytes. On the 4th data packet, which was send from the listening post to the victim computer, the Escrow address was sent along with other bytes of information. The victim identification is found in two data packets, the first, in the middle of the data, and on the third packet, also with other information. Knowing this let us move on to analysing the binary that send the packets, libclient_comms.so. with ghidra.
After decompiling the dynamic linux library, we come up with a list of functions, in the Symbol Tree window. The most important being the connect function which is probably called before sending, with the send function.

Hitting Ctrl+Shift+F to show the references to the function.

The function that makes the connection is start_client.

Here is the relevant part of the function:

  // /\/\/\/\ More code /\/\/\/\
  if ((local_878 == 0) || (iVar2 = connect(local_878,(sockaddr *)&local_eb8,0x10), iVar2 < 0)) {
  /* 
   *  More code ...
   */
  }
  do {
    /* 
     *  More code ...
     */
    switch(local_ea8[0]) {
    /* 
     *  More code ...
     */
    case 2:
      /* 
       *  More code ...
       */
      iVar2 = enc_ki(local_348,0x200);
      if ((iVar2 == 0) && (iVar2 = bcvh(&local_ebc,1,local_718,3), iVar2 == 0)) {
        iVar2 = bcvh(local_e90,4,&local_6f8,9);
        if (iVar2 == 0) {
          iVar2 = cid(local_e90,local_874,&local_708);
          if ((iVar2 == 0) && (iVar2 = bcvh(local_874,0x20,&local_6e8,0x41), iVar2 == 0)) {
            /* 
             *  More code ...
             */
            }
            iVar2 = c_hh(&local_648,0x250,&local_698,0x40);
            if (iVar2 == 0) {
              /* 
               *  More code ...
               */
              }
              uVar5 = FUN_00100b30((long)local_ea8);
  // \/\/\/\/ More code \/\/\/\/ 

Notice, in the code after the connect function, the enc_ki function is called then the bcvh function is called a couple of time, followed by cid and c_hh. In the function FUN_00100b30, resides the first call to send function. So, we can make the assumption that what ever is produced from the functions above is sent in the first data packet, which is comparatively large. Judging from the name enc_ki creates the encrypted the $0\mathrm{x}200$ hex number could be the number of bytes in the key, 512. I have no idea what bcvh does. Both cid and c_hh are called from libclient_crypto.so library. And, if we look at the decompiled C code:

undefined8 cid(undefined4 *puParm1,undefined8 *puParm2,undefined4 *puParm3)
{
  /* 
   *  More code ...
   */
  if (puParm1 == (undefined4 *)0x0) {
    gia(local_b8);
  }
  else {
    local_b8[0] = *puParm1;
  }
  iVar1 = get_totp_token(key,(ulong)local_c0,(ulong)key_len,&local_bc);
  if (iVar1 == 1) {
    iVar1 = __snprintf_chk(&local_a8,7,1,7,&DAT_001020dd,(ulong)local_bc);
    key_len = local_c0;
    if (iVar1 != 6) goto LAB_00101b5e;
    local_98 = CONCAT44(local_a8,local_b8[0]);
    local_90 = local_a4;
    evp_md = EVP_sha256();
    puVar2 = HMAC(evp_md,key,key_len,
      (uchar *)&local_98,10,(uchar *)&local_88,&local_c4);
    if (puVar2 == (uchar *)0x0) goto LAB_00101b5e;
    *puParm2 = local_88;
    puParm2[1] = local_80;
    puParm2[2] = local_78;
    puParm2[3] = local_70;
    *puParm3 = local_a8;
// \/\/\/\/ More code \/\/\/\/

From the code above, we see the first parameter's pointer, puParam1, is assigned to local_b8 or if it is null then it calls the function gia to acquire it. Later on it is concatenated with local_a8 which is first written to by __snprintf_chk which is a version of snprintf that stores the value local_bc as a C string in local_a8. local_bc has the totp judging from the name of the function get_totp_token. So, puParm3 is the parameter that transports the totp. we see that the totp is concatenated with the output of gia and an HMAC-SHA256 is created from it, puParam2 exports this value. local_b8 is declared with 4 bytes, which gives us an idea of what might be stored there, *cough* ipaddress *cough*.

Here is the relevant code pertaining to figuring out what the first parameter of cid in start_client is:

// /\/\/\/\ More code /\/\/\/\
iVar2 = getsockname(local_878,(sockaddr *)&local_728,&local_ebc);
if (iVar2 < 0) goto LAB_00100ee0;
local_e90[0] = local_728._4_4_;
/* 
 *  More code ...
 */
if ((iVar2 == 0) && (iVar2 = bcvh(&local_ebc,1,local_718,3), iVar2 == 0)) {
  iVar2 = bcvh(local_e90,4,&local_6f8,9);
    if (iVar2 == 0) {
      iVar2 = cid(local_e90,local_874,&local_708);
// \/\/\/\/ More code \/\/\/\/

You can see that the first parameter of cid is called local_e90 here which, if we track it back, it is used by bcvh, still no clue what it does, but before then it is assigned to by local_728; that is used as a parameter by getsockname, that is a native function whose documentation is found here. In the 2nd parameter of that function, a sockaddr struct is taken that according to here could store the port and the IP Address. The port only requires 2 bytes so, since the variable mentioned before uses 4 bytes, it probably is the IP Address.

As for the size of the totp, we can take a look at the __snprintf_chk function and see that the parameter DAT_001020dd points to the string "06u", meaning the character string will be 6 integers in length.

Anyway, we can make an educated guess that in the packet first data packet the ip address, the victim id, and the totp is stored in that order. To check we get the first 4 bytes, 0a 09 12 f1 which translates to 10 9 18 241 in decimal, like our ip address 10.9.18.241. In turn the topt is 625369.

There really only is one data packet in transmissions between the victim and the listening post that can store the encrypted key, the first one, and one place in the packet where it can be stored, after the totp. So, our encrypted key is:

9df21ab61957430e8e8270082db41bc22dd8c66eba7f3287c59eaebda99ddb0845bb2b2cd5f796fa9e819fa19201b0fd03df9b24de3f218cf1b9f9255dd2633490b89129047d6f1c873777df6166306608094657ce3b61c1f60f771d507a17f2cb19ff9aaaab822e744d77b11f7270d1e4a46f2e030ec70d272b70dff0cf181fa8a17973772547f01f5dad7fb4c21bdeb87017dd054e9da0f0c6cbd1f9cb2bc03b44bfe548e68857b31fe41360d502a95262f5c2e68089e6cd9328e424c80c3fa36bd7d1d63070c63c9e5782e9b642f3499e30cbdfb26167b587f1d0ca72edd7c808801b2cfe09edec539fd3e13d4dfbbacd1c9b0c1f970ea02e40aa2e6d9021