This task involve the reverse engineering of a specific function. A lot of the decompiled code is complicated rearing on incomprehensible so, I think it is best to find and use clues to our advantage, like a detective.

Task 3

In task 3, we are asked to reverse-engineer the creation of the process of the creation of the victim ID by the ransomware. Again, we are given the two library, the communication library, libclient_comms.so, and the cryptographic library, libclient_crypt.so, but, we are also given the information of another computer. We are to calculate the victim ID of that computer.

Fortunately, we have that same information from the previous tasks that we can use to test our code. Here is the victim information I was given:

{
    "cpu_bits": "32",
    "ip_address": "10.100.230.248",
    "mac_address": "4a:c8:9a:d0:21:04",
    "operating_system": "Windows",
    "otp_value": "148342",
    "time_of_infection": "Mon, 13 Aug 2018 05:12:12 GMT"
}

Reverse engineering

Let's open up libclient_crypt.so in Ghidra's code browser. In the last NSA Codebreaker challenge post (link),  we found out that the victim id was genetrated by the cid function. So, find and open it up in the decompiler window. We see that in the function another function called FUN_00101930 is called which we found out in the first Codebreaker challenge post (link) is the function that returns the OTP. We can also change the return variable name to reflect it. The function gia returns the ip address, so we can also change that variable. We can, by looking up the OpenSSL documentation for the functions in get_totp_token identify the variables carrying information the sizes, so we can rename them as such. here is the result for that part of the code.

if (ip_param == (undefined4 *)0x0) {
  gia(ip_address);
}
else {
  ip_address[0] = *ip_param;
}
uVar3 = 1;
epoch = epochtime();
get_otp_token((long)&otp,0x21);
otp_dec = (uchar *)base32_decode((byte *)&otp,&otp_size);
if (key == (uchar *)0x0) goto LAB_00101b6b;
uVar3 = get_totp_token(otp_dec,(ulong)otp_size,epoch,&totp);

We see that the otp is base32 decoded and stored in the key variable with the length otp_size. The TOTP is then acquired and stored in the totp variable.

The TOTP is then transformed from an integer to a character array with the __snprintf_chk function call. I changed the name of the output character pointer accordingly

if ((int)uVar3 == 1) {
  iVar1 = __snprintf_chk(&totp_str,7,1,7,&DAT_001020dd,(ulong)totp);
  key_len = otp_size;

The TOTP and the ip address are concatenated resulting in a character array containing first the ip address then the TOTP stored in the ip_totp variable which I renamed.

if (iVar1 != 6) goto LAB_00101b5e;
ip_totp = CONCAT44(totp_str,ip_address[0]);
local_90 = local_a4;

The HMAC OpenSSL function is then called. We can look in the OpenSSL decumentation for guidance as to where the output hmac is. I changed the variable names accordinly. It turns out the hmac which is the victim id is stored in the md variable.

evp_md = EVP_sha256();
puVar2 = HMAC(evp_md,otp_dec,key_len,(uchar *)&totp_ip,10,(uchar *)&md,&len);
if (puVar2 == (uchar *)0x0) goto LAB_00101b5e;

We see that the victim id is the sha 256 hmac generated from the OTP being the key and the ip address and TOTP concatenation is the message in the hmac.

So, to recreate the victim id, firstly, we need to decode the base32 encoded OTP string, get the TOTP, transform that TOTP into a string, concatenate the IP address and the TOTP string into a single string, and finally create an SHA256 HMAC with the OTP being the key and the IP address and TOTP concatenation being the message. We can easily do this in Java.

Let's open up a gradle project as we will need to bring in some dependencies from apache commons libraries, including the codec library.

dependencies {
    compile group: 'commons-codec', name: 'commons-codec', version: '1.12'
}

let's start by creating a NSA Codebreaker class and import the following classes.

import java.util.Scanner;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base32;
import org.apache.commons.codec.binary.Hex;

public class NSACodebreaker {
  public static void main(String[] args) {
  }
}

First we need to create a private function within the class that will convert our ip address into a byte array.

private static byte[] IPBytes(String ipAddress) {
  String[] spl = ipAddress.split("\\.");
  byte[] retBytes = new byte[4];
  for (int i = 0; i < 4; i++)
    retBytes[i] = (byte)Integer.parseInt(spl[i]);
  return retBytes;
}

In the main function, let's get needed information from the user.

// Get our information
Scanner scan = new Scanner(System.in);
String otpStr = scan.nextLine();
String ipaddressStr = scan.nextLine();
String totpStr = scan.nextLine();

Then we convert the ip address string to a byte array with out function

// IP Address Bytes
byte[] ipaddressBytes = IPBytes(ipaddressStr);

Decode the OTP from base32 into a byte array

// Decode otp from base32
Base32 base32 = new Base32();
byte[] otpDecoded = base32.decode(otpStr);

Convert the TOTP string to bytes

// Get TOTP bytes
byte[] totpBytes = totpStr.getBytes();

Concatenate the IP address and the TOTP

byte[] ip_totp = new byte[ipaddressBytes.length + totpBytes.length];
System.arraycopy(ipaddressBytes, 0, ip_totp, 0, ipaddressBytes.length);
System.arraycopy(totpBytes, 0, ip_totp, ipaddressBytes.length, totpBytes.length);

Finally, in a try and catch scope, create an Mac instance, a the key, and initiate the Mac

try {
  Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
  SecretKeySpec secret_key = new SecretKeySpec(optDecoded, "HmacSHA256");
  sha256_HMAC.init(secret_key);

Finally, get the victim id

byte[] victimID = sha256_HMAC.doFinal(ip_totp);

and display it

System.out.println(Hex.encodeHex(victimID));

Here is the full source code:

import java.util.Scanner;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base32;
import org.apache.commons.codec.binary.Hex;

public class NSACodebreaker {
  public static void main(String[] args) {
    // Get our information
    Scanner scan = new Scanner(System.in);
    String otpStr = scan.nextLine();
    String ipaddressStr = scan.nextLine();
    String totpStr = scan.nextLine();

    // IP Address Bytes
    byte[] ipaddressBytes = IPBytes(ipaddressStr);

    // Decode otp from base32
    Base32 base32 = new Base32();
    byte[] otp_decoded = base32.decode(otpStr);

    // Get TOTP bytes
    byte[] totpBytes = totpStr.getBytes();

    // Concatenate the ip address and the totp
    byte[] ip_totp = new byte[ipaddressBytes.length + totpBytes.length];
    System.arraycopy(ipaddressBytes, 0, ip_totp, 0, ipaddressBytes.length);
    System.arraycopy(totpBytes, 0, ip_totp, ipaddressBytes.length, totpBytes.length);

    try {
      Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
      SecretKeySpec secret_key = new SecretKeySpec(otp_decoded, "HmacSHA256");
      sha256_HMAC.init(secret_key);

      // Get victim ID
      byte[] victimID = sha256_HMAC.doFinal(ip_totp);

      System.out.println(Hex.encodeHex(victimID));
    } catch (Exception ex) {
      ex.printStackTrace(System.err);
    }
  }

  private static byte[] IPBytes(String ipAddress) {
    String[] spl = ipAddress.split("\\.");
    byte[] retBytes = new byte[4];
    for (int i = 0; i < 4; i++)
      retBytes[i] = (byte)Integer.parseInt(spl[i]);
    return retBytes;
  }
}

And the decompiled cid function

undefined8 cid(undefined4 *ip_param,undefined8 *param_2,undefined4 *param_3)
{
  uint key_len;
  int epoch;
  int iVar1;
  uchar *otp_dec;
  EVP_MD *evp_md;
  uchar *puVar2;
  undefined8 uVar3;
  long in_FS_OFFSET;
  uint len;
  uint otp_size;
  uint totp;
  undefined4 ip_address [4];
  undefined4 totp_str;
  undefined2 local_a4;
  undefined local_a2;
  undefined8 ip_totp;
  undefined2 local_90;
  undefined8 md;
  undefined8 local_80;
  undefined8 local_78;
  undefined8 local_70;
  undefined8 otp;
  undefined8 local_60;
  undefined8 local_58;
  undefined8 local_50;
  undefined local_48;
  long local_40;
  
  local_40 = *(long *)(in_FS_OFFSET + 0x28);
  len = 0;
  ip_address[0] = 0;
  totp_str = 0;
  local_a4 = 0;
  local_a2 = 0;
  md = 0;
  local_80 = 0;
  local_78 = 0;
  local_70 = 0;
  otp_size = 0;
  ip_totp = 0;
  local_90 = 0;
  totp = 0;
  otp = 0;
  local_60 = 0;
  local_58 = 0;
  local_50 = 0;
  local_48 = 0;
  if (ip_param == (undefined4 *)0x0) {
    gia(ip_address);
  }
  else {
    ip_address[0] = *ip_param;
  }
  uVar3 = 1;
  epoch = epochtime();
  get_otp_token((long)&otp,0x21);
  otp_dec = (uchar *)base32_decode((byte *)&otp,&otp_size);
  if (otp_dec == (uchar *)0x0) goto LAB_00101b6b;
  uVar3 = get_totp_token(otp_dec,(ulong)otp_size,epoch,&totp);
  if ((int)uVar3 == 1) {
    iVar1 = __snprintf_chk(&totp_str,7,1,7,&DAT_001020dd,(ulong)totp);
    key_len = otp_size;
    if (iVar1 != 6) goto LAB_00101b5e;
    ip_totp = CONCAT44(totp_str,ip_address[0]);
    local_90 = local_a4;
    evp_md = EVP_sha256();
    puVar2 = HMAC(evp_md,otp_dec,key_len,(uchar *)&ip_totp,10,(uchar *)&md,&len);
    if (puVar2 == (uchar *)0x0) goto LAB_00101b5e;
    *param_2 = md;
    param_2[1] = local_80;
    param_2[2] = local_78;
    param_2[3] = local_70;
    *param_3 = totp_str;
    uVar3 = 0;
    *(undefined2 *)(param_3 + 1) = local_a4;
  }
  else {
LAB_00101b5e:
    uVar3 = 1;
  }
  free(otp_dec);
LAB_00101b6b:
  if (local_40 == *(long *)(in_FS_OFFSET + 0x28)) {
    return uVar3;
  }
  __stack_chk_fail();
}