Writeup - Simply Unstable

Challenge Details

Author: Patrick Kuin

Category: Reversing

Platform: StudSec CTF Platform

Binary Information: ELF, Not Stripped, X86_64

I will open the binary in Ghidra (disassembler) and analyze it.

Main Function

undefined8 main(int param_1,undefined8 *param_2,undefined8 param_3,uchar *param_4,size_t param_5) {
  undefined8 uVar1;
  ulong uVar2;
  size_t *outlen;
  uchar *out;

  if (param_1 < 2) {
    printf("Usage: %s hex_key",*param_2);
    uVar1 = 1;
  } else {
    out = (uchar *)0x0;
    uVar2 = strtol((char *)param_2[1],(char **)0x0,0x10);
    decrypt((EVP_PKEY_CTX *)(uVar2 & 0xffffffff),out,outlen,param_4,param_5);

    if (flag_ciphertext == -0x1a76b7ab) {
      (*(code *)&flag_ciphertext)();
      putchar(10);
    } else {
      puts("Invalid key");
    }
    uVar1 = 0;
  }
  return uVar1;
}

Decrypt Function

int decrypt(EVP_PKEY_CTX *ctx,uchar *out,size_t *outlen,uchar *in,size_t inlen) {
  int iVar1;
  long lVar2;
  uint local_28;

  lVar2 = sysconf(0x1e);
  iVar1 = mprotect((void *)(-lVar2 & 0x104020U),(long)(0x104020 - (int)(void *)(-lVar2 & 0x104020U)),7);
  
  if (iVar1 < 0) {
    perror("mprotect:");
  }
  
  for (local_28 = 0; local_28 < 0x18; local_28 = local_28 + 1) {
    (&flag_ciphertext)[(int)local_28] = (&flag_ciphertext)[(int)local_28] ^ (uint)ctx;
  }
  
  return local_28;
}

Solution Approach

To solve this challenge, we need to XOR the initial value of .secret with the target value:

Initial value of .secret (24 bytes): 0x413c8c81

Target value: 0xe5894855

Gathering Initial Value of .secret

pwndbg> info files
Symbols from "/home/kali/Documents/studsec/simply_unstable/Handout/challenge".
Local exec file:
    `/home/kali/Documents/studsec/simply_unstable/Handout/challenge', file type elf64-x86-64.
    . . .
    0x0000555555558020 - 0x0000555555558082 is .secret

XOR Calculation

Using the first 24 bytes from .secret:

pwndbg> x/24xb 0x0000555555558020
0x555555558020 <flag_ciphertext>:    0x81    0x8c    0x3c    0x41    0x9c    0x49    0xe0    0x44
0x555555558028 <flag_ciphertext+8>:    0x9c    0x4d    0x62    0xec    0x6d    0x85    0xf4    0xe5
0x555555558030 <flag_ciphertext+16>:    0x95    0x85    0xf4    0xe5    0x95    0x8c    0x0d    0xa6

With endianness, we format it as: 0x413c8c81

Final XOR Calculation Script

initial_value = 0x413c8c81
target_value = 0xe5894855
X = initial_value ^ target_value
print(f"X should be: {hex(X)}")

The calculated value from the script: 0xa4b5c4d4

Testing the value:

./challenge 0xa4b5c4d4

Flag obtained: CTF{c0de_b3_unst@ble}