Hackvent 2019: Day 18

Hackvent 2019190

Challenge

HV19.18 Dance with me

Introduction
Santa had some fun and created todays present with a special dance. this is what he made up for you:
096CD446EBC8E04D2FDE299BE44F322863F7A37C18763554EEE4C99C3FAD15

Dance with him to recover the flag.

Resource mirror: HV19-Day18-dance.zip

Solution

In our zip file we get a dance binary that we discover is an arm binary. After some digging around we find out that it is in fact a DEB and written for iOS. We attempt to run the code in an emulator like QEMU but unfortunately don't have much luck with getting the emulator to work. Instead we rely on static analysis.

We use IDA's ARM decompiler to give us the Objective C code belonging to the binary. As I didn't have the required IDA plugin I got this from BlindHero (thanks!).

This was the code:

#include <cstring>
#include <cstdio>

typedef long long int __int64;
typedef long int _DWORD;
typedef unsigned long int uint32;
typedef unsigned int uint;
typedef unsigned char _BYTE;
typedef unsigned char __int8;

template<class T> T __ROL__(T value, int count)
{
  const uint nbits = sizeof(T) * 8;

  if ( count > 0 )
  {
    count %= nbits;
    T high = value >> (nbits - count);
    if ( T(-1) < 0 ) // signed value
      high &= ~((T(-1) << count));
    value <<= count;
    value |= high;
  }
  else
  {
    count = -count % nbits;
    T low = value << (nbits - count);
    value >>= count;
    value |= low;
  }
  return value;
}

inline uint32 __ROR4__(uint32 value, int count) { return __ROL__((uint32)value, -count); }

__int64 dance_words(__int64 result, __int64 a2)
{
  __int64 v2; // x8
  int v3; // w6
  int v4; // w7
  int v5; // w8
  int v6; // w14
  int v7; // w16
  int v8; // w17
  int v9; // w3
  int v10; // w5
  int v11; // w12
  int v12; // w13
  int v13; // w2
  int v14; // w15
  int v15; // w4
  int v16; // w19
  signed int v17; // w11
  int v18; // w9
  int v19; // w10
  int v20; // w17
  int v21; // w5
  int v22; // w7
  int v23; // w14
  int v24; // w3
  int v25; // w6
  int v26; // w8
  int v27; // w16
  int v28; // w19
  int v29; // w10
  int v30; // w13
  int v31; // w2
  int v32; // w9
  int v33; // w12
  int v34; // w15
  int v35; // w4
  __int64 v36; // x11
  int v37; // [xsp+8h] [xbp-58h]
  int v38; // [xsp+Ch] [xbp-54h]
  int v39; // [xsp+10h] [xbp-50h]
  int v40; // [xsp+14h] [xbp-4Ch]
  int v41; // [xsp+18h] [xbp-48h]
  int v42; // [xsp+1Ch] [xbp-44h]
  int v43; // [xsp+20h] [xbp-40h]
  int v44; // [xsp+24h] [xbp-3Ch]
  int v45; // [xsp+28h] [xbp-38h]
  int v46; // [xsp+2Ch] [xbp-34h]
  int v47; // [xsp+30h] [xbp-30h]
  int v48; // [xsp+34h] [xbp-2Ch]
  int v49; // [xsp+38h] [xbp-28h]
  int v50; // [xsp+3Ch] [xbp-24h]
  int v51; // [xsp+40h] [xbp-20h]
  int v52; // [xsp+44h] [xbp-1Ch]

  v2 = 0LL;
  do
  {
    *(&v37 + 4 * ((unsigned int)v2 >> 2) + (v2 & 3)) = *(_DWORD *)(a2 + 4 * v2);
    ++v2;
  }
  while ( v2 != 16 );
  v4 = v49;
  v3 = v50;
  v6 = v37;
  v5 = v38;
  v8 = v41;
  v7 = v42;
  v10 = v45;
  v9 = v46;
  v12 = v43;
  v11 = v44;
  v13 = v47;
  v14 = v48;
  v16 = v51;
  v15 = v52;
  v17 = 10;
  v19 = v39;
  v18 = v40;
  do
  {
    v20 = v8 ^ __ROR4__(v6 + v4, 25);
    v21 = v10 ^ __ROR4__(v20 + v6, 23);
    v22 = v4 ^ __ROR4__(v21 + v20, 19);
    v23 = v6 ^ __ROR4__(v22 + v21, 14);
    v24 = v9 ^ __ROR4__(v7 + v5, 25);
    v25 = v3 ^ __ROR4__(v24 + v7, 23);
    v26 = v5 ^ __ROR4__(v25 + v24, 19);
    v27 = v7 ^ __ROR4__(v26 + v25, 14);
    v28 = v16 ^ __ROR4__(v13 + v12, 25);
    v29 = v19 ^ __ROR4__(v28 + v13, 23);
    v30 = v12 ^ __ROR4__(v29 + v28, 19);
    v31 = v13 ^ __ROR4__(v30 + v29, 14);
    v32 = v18 ^ __ROR4__(v15 + v14, 25);
    v33 = v11 ^ __ROR4__(v32 + v15, 23);
    v34 = v14 ^ __ROR4__(v33 + v32, 19);
    v35 = v15 ^ __ROR4__(v34 + v33, 14);
    v5 = v26 ^ __ROR4__(v32 + v23, 25);
    v19 = v29 ^ __ROR4__(v5 + v23, 23);
    v18 = v32 ^ __ROR4__(v19 + v5, 19);
    v6 = v23 ^ __ROR4__(v18 + v19, 14);
    v12 = v30 ^ __ROR4__(v27 + v20, 25);
    v11 = v33 ^ __ROR4__(v12 + v27, 23);
    v8 = v20 ^ __ROR4__(v11 + v12, 19);
    v7 = v27 ^ __ROR4__(v8 + v11, 14);
    v14 = v34 ^ __ROR4__(v31 + v24, 25);
    v10 = v21 ^ __ROR4__(v14 + v31, 23);
    v9 = v24 ^ __ROR4__(v10 + v14, 19);
    v13 = v31 ^ __ROR4__(v9 + v10, 14);
    v4 = v22 ^ __ROR4__(v35 + v28, 25);
    v3 = v25 ^ __ROR4__(v4 + v35, 23);
    v16 = v28 ^ __ROR4__(v3 + v4, 19);
    v15 = v35 ^ __ROR4__(v16 + v3, 14);
    --v17;
  }
  while ( v17 );
  v36 = 0LL;
  v49 = v4;
  v50 = v3;
  v37 = v6;
  v38 = v5;
  v41 = v8;
  v42 = v7;
  v45 = v10;
  v46 = v9;
  v43 = v12;
  v44 = v11;
  v47 = v13;
  v48 = v14;
  v51 = v16;
  v52 = v15;
  v39 = v19;
  v40 = v18;
  do
  {
    *(_DWORD *)(result + 4 * v36) = *(_DWORD *)(a2 + 4 * v36) + *(&v37 + 4 * ((unsigned int)v36 >> 2) + (v36 & 3));
    ++v36;
  }
  while ( v36 != 16 );
  return result;
}

__int64 dance_block(__int64 a1, int *a2, __int64 a3, __int64 a4)
{
  __int64 v4; // x19
  __int64 result; // x0
  int v6; // w8
  __int64 v7; // x9
  char v8[64]; // [xsp+8h] [xbp-98h]
  int v9; // [xsp+48h] [xbp-58h]
  int v10; // [xsp+4Ch] [xbp-54h]
  int v11; // [xsp+50h] [xbp-50h]
  int v12; // [xsp+54h] [xbp-4Ch]
  int v13; // [xsp+58h] [xbp-48h]
  int v14; // [xsp+5Ch] [xbp-44h]
  __int64 v15; // [xsp+60h] [xbp-40h]
  __int64 v16; // [xsp+68h] [xbp-38h]
  int v17; // [xsp+70h] [xbp-30h]
  int v18; // [xsp+74h] [xbp-2Ch]
  int v19; // [xsp+78h] [xbp-28h]
  int v20; // [xsp+7Ch] [xbp-24h]
  int v21; // [xsp+80h] [xbp-20h]
  int v22; // [xsp+84h] [xbp-1Ch]

  v4 = a1;
  v9 = 1634760805;
  v10 = *a2;
  v11 = a2[1];
  v12 = a2[2];
  v13 = a2[3];
  v14 = 857760878;
  v15 = a3;
  v16 = a4;
  v17 = 2036477234;
  v18 = a2[4];
  v19 = a2[5];
  v20 = a2[6];
  v21 = a2[7];
  v22 = 1797285236;
  result = dance_words((__int64)v8, (__int64)&v9);
  v6 = 0;
  v7 = 0LL;
  do
  {
    *(_BYTE *)(v4 + v7) = *(_DWORD *)&v8[4 * ((unsigned int)v7 >> 2)] >> (v6 & 0x18);
    ++v7;
    v6 += 8;
  }
  while ( v7 != 64 );
  return result;
}

__int64 dance(__int64 result, __int64 length, __int64 a3, __int64 a4)
{
  __int64 v4; // x19
  int *v5; // x20
  __int64 v6; // x21
  __int64 v7; // x22
  __int64 v8; // x23
  char v9[64]; // [xsp+8h] [xbp-88h]

  if ( length )
  {
    v4 = a4;
    v5 = (int *)a3;
    v6 = length;
    v7 = result;
    v8 = 0LL;
    do
    {
      if ( !(v8 & 0x3F) )
        result = dance_block((__int64)v9, v5, v4, (unsigned int)v8 >> 6);
      *(_BYTE *)(v7 + v8) ^= v9[v8 & 0x3F];
      ++v8;
    }
    while ( v6 != v8 );
  }
  return result;
}

unsigned char unk_100007F50[] = { 0x03, 0x20, 0x63, 0x46, 0x61, 0xB6, 0x3C, 0xAF, 0xAA, 0x76, 0xC2, 0x7E, 0xEA, 0x00, 0xB5, 0x98 };
unsigned char unk_100007F80[] = { 0xAD, 0xF1, 0x6C, 0x63, 0x45, 0x6A, 0x6E, 0xF1, 0xED, 0x90, 0x79, 0x46, 0x9D, 0xA2, 0xA0, 0xB5 };
unsigned char unk_100007F60[] = { 0xFB, 0x2F, 0x70, 0x97, 0x21, 0x4F, 0xD0, 0x4C, 0xB2, 0x57, 0xAC, 0x29, 0x04, 0xEF, 0xEE, 0x46 };
unsigned char unk_100007F70[] = { 0x79, 0x73, 0x0F, 0xF4, 0xEC, 0x0C, 0x40, 0x6B, 0xFD, 0x91, 0xC9, 0x1F, 0xE7, 0x04, 0x00, 0xA8 };

int main(int argc, const char **argv, const char **envp)
{
  size_t input_length; // x19
  size_t v4; // x21
  int result; // w0
  char v6; // [xsp+10h] [xbp-D0h]
  unsigned char v7[32]; // [xsp+30h] [xbp-B0h]
  __int128 v8; // [xsp+40h] [xbp-A0h]
  __int128 v9; // [xsp+50h] [xbp-90h]
  __int128 v10; // [xsp+60h] [xbp-80h]
  unsigned char* v11; // [xsp+70h] [xbp-70h]
  unsigned char* v12; // [xsp+80h] [xbp-60h]
  unsigned char* v13; // [xsp+90h] [xbp-50h]
  unsigned char* v14; // [xsp+A0h] [xbp-40h]
  __int64 v15; // [xsp+B8h] [xbp-28h]

  v13 = unk_100007F70;
  v14 = unk_100007F80;
  v11 = unk_100007F50;
  v12 = unk_100007F60;
  v9 = 0u;
  v10 = 0u;
  // v7 = 0u;
  v8 = 0u;
  printf("Input your flag: ", argv, envp);
  fgets(&v6, 32, stdin);
  input_length = strlen(&v6);
  if ( input_length )
    memcpy(&v7, &v6, input_length);
  dance((__int64)&v7, input_length, (__int64)&v11, -5678246756302764783LL);
  if ( strlen(&v6) )
  {
    v4 = 0LL;
    do
      printf("%02X", *((unsigned __int8 *)&v7 + v4++));
    while ( strlen(&v6) > v4 );
  }
  result = putchar(10);
  return result;
}

It takes a while to analyse this code to learn what cipher is actually being used.
Through many clues we learn its a stream cipher and the appropriately named Salsa20 cipher.
At this point its reasonable to assume we need to decrypt our encrypted flag 096CD446EBC8E04D2FDE299BE44F322863F7A37C18763554EEE4C99C3FAD15 which is just hex data using the Salsa20 algorithm and some key and nonce. We are looking for a 128 bit or 256 bit key and 64 bit nonce. We can see four arguments passed to the dance method. The first is the result and the second is simply the input length used to check against loop guards. The last two arguments are our key and nonce. We take the longer length argument &v11 as our nonce.

We use IDA to easily fetch the key as raw data:

\x03\x20\x63\x46\x61\xB6\x3C\xAF\xAA\x76\xC2\x7E\xEA\x00\xB5\x9B\xFB\x2F\x70\x97\x21\x4F\xD0\x4C\xB2\x57\xAC\x29\x04\xEF\xEE\x46\x79\x73\x0F\xF4\xEC\x0C\x40\x6B\xFD\x91\xC9\x1F\xE7\x04\x00\xA8\xAD\xF1\x6C\x63\x45\x6A\x5E\xF1\xED\x9D\x79\x46\x9D\xA2\xA0\xB5

As it turns out only the upper (first) 32 bytes of this key are used.
Our nonce is the number -5678246756302764783 which we convert to hex as \xB1\x32\xD0\xA8\xE7\x8F\x45\x11.  However, we are using little endian ordering so we reverse the order of bytes to \x11\x45\x8F\xE7\xA8\xD0\x32\xB1.

Finally we can write a python script to decode our Salsa20 encoded string. We simply use a template from online:

# Hackvent 2019 - Day 18
# Mo Beigi (https://mobeigi.com)
from Crypto.Cipher import Salsa20

key = b'\x03\x20\x63\x46\x61\xB6\x3C\xAF\xAA\x76\xC2\x7E\xEA\x00\xB5\x9B\xFB\x2F\x70\x97\x21\x4F\xD0\x4C\xB2\x57\xAC\x29\x04\xEF\xEE\x46'
nonce = b'\x11\x45\x8F\xE7\xA8\xD0\x32\xB1'

ciphertext = b'\x09\x6C\xD4\x46\xEB\xC8\xE0\x4D\x2F\xDE\x29\x9B\xE4\x4F\x32\x28\x63\xF7\xA3\x7C\x18\x76\x35\x54\xEE\xE4\xC9\x9C\x3F\xAD\x15'

cipher = Salsa20.new(key=key, nonce=nonce)
plaintext = cipher.decrypt(ciphertext)

print(plaintext)

Running this prints out our daily flag!

Flag:

HV19{Danc1ng_Salsa_in_ass3mbly}

Leave a comment

(required)(will not be published)(required)

Comments

There are no comments yet. Be the first to add one!