Skip to main content
  1. CTF Writeups/
  2. scriptCTF 2025/

PlasticShield

·
Rev Aes Hash
subzcuber
Author
subzcuber
i like to imagine i’m funny

Author: Ashray Shah

OPSec is useless unless you do it correctly.


given a binary, on decompiling we can see quite a straightforward attack (variables renamed and comments added)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
int32_t main(int32_t argc, char **argv, char **envp) {
  // ENTER PASSWORD
  printf("Please enter the password: ");
  char buffer[0x107];
  scanf("%255s", &buffer);

  // COMPUTE INDEX OF KEY
  int64_t rax_6;
  int64_t rdx;
  rdx = HIGHQ(((strlen(&buffer) * 0x3c) >> 2) * 0x28f5c28f5c28f5c3);
  rax_6 = LOWQ(((strlen(&buffer) * 0x3c) >> 2) * 0x28f5c28f5c28f5c3);
  char key_char = buffer[rdx >> 2];

  // HASH KEY
  char key_hash[0x40];
  crypto_blake2b(&key_hash, 0x40, &key_char, 1);
  char key_hash_hex;

  for (int64_t i = 0; i <= 0x3f; i += 1)
    sprintf(i * 2 + &key_hash_hex, "%02x", key_hash[i]);

  // DECRYPT CIPHERTEXT
  char var_198 = 0;
  void *const ciphertext_hash =
      "713d7f2c0f502f485a8af0c284bd3f1e7b03d27204a616a8340beaae23f130edf65401c1"
      "f99fe99f63486a385ccea217";
  int64_t key_bytes;
  hex_to_bytes(&key_hash_hex, &key_bytes, 0x20);
  int64_t aes_iv_bytes;
  char aes_iv_hex;
  hex_to_bytes(&aes_iv_hex, &aes_iv_bytes, 0x10);
  uint64_t ct_len = strlen(ciphertext_hash) >> 1;
  int64_t *ct_bytes = malloc(ct_len);
  hex_to_bytes(ciphertext_hash, ct_bytes, ct_len);
  char var_348;
  AES_init_ctx_iv(&var_348, &key_bytes, &aes_iv_bytes);
  AES_CBC_decrypt_buffer(&var_348, ct_bytes, ct_len);
  char rax_26 = *(ct_bytes + ct_len - 1);

  if (rax_26 <= 0x10 && rax_26)
    ct_len -= rax_26;

  printf("Decrypted text: ");

  for (int i_1 = 0; i_1 < ct_len; i_1 += 1)
    putchar(*(i_1 + ct_bytes));

  putchar(0xa);
  free(ct_bytes);
  return 0;
}

All the binary does is extract one character from our input password and hash it to use as the key for an AES CBC decryption. So the simple solution is to bruteforce over all possible characters

Here’s a bash oneliner to solve it

for i in {32..127}; do echo "$i" | awk '{printf("%c", $0);}' | ./plastic-shield; done | rg -a -e "script"
Please enter the password: Decrypted text: scriptCTF{20_cau541i71e5_d3f3n5es_d0wn}

Initially I tried it solve it purely statically by trying to extract the IV with gdb then bruteforcing with python

solve.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from Crypto.Cipher import AES
from Crypto.Hash import BLAKE2b
from string import printable
from Crypto.Util.number import long_to_bytes

ct = "713d7f2c0f502f485a8af0c284bd3f1e7b03d27204a616a8340beaae23f130edf65401c1f99fe99f63486a385ccea217"
iv = "d5abe2c6b1b5ee3face62fed78dbef802f2a85cb91d455a8f5249d330853cb3c"

ct = int(ct, 0x10)
ct = long_to_bytes(ct)
iv = int(iv[0:0x20], 0x10)
iv = long_to_bytes(iv)

hash_dict = {}
for ch in printable:
    hasher = BLAKE2b.new()
    hash_dict[ch] = hasher.update(ch.encode()).digest()[0:0x20]

for ch, hash in hash_dict.items():
    print(f"{ch=} | ", end='')
    aes = AES.new(hash, AES.MODE_CBC, iv)
    print(aes.decrypt(ct))

However i’m pretty sure the IV is wrong since i only get a partial flag on input “`”, so either I’m missing something or i just messed up getting the IV. Because even in the decompilation the IV doesn’t seem to be initialized anywhere.

Reply by Email

Related

Its Locked
Rev 453pt 98 Solves Perl Obfuscation
this was fun
Deflation Gangster
Rev 364pt 166 Solves
Blue Magic
FlagsFlagsFlags
Rev 97pt 285 Solves Upx Pwntools
100k flags 💀