# rev

## Challenges

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FDSHEIV9G9IVxGr504z0u%2Fimage.png?alt=media&#x26;token=7841ca04-9a0d-4a14-8168-0f62e8efeb74" alt=""><figcaption></figcaption></figure>

### Plastic Shield

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FMO3AM03fRUpB6jxRUx3Y%2Fimage.png?alt=media&#x26;token=63a5e16c-7339-47f0-bd03-e35cd3d6e3ac" alt=""><figcaption></figcaption></figure>

> OPSec is useless unless you do it correctly.
>
> * [plastic-shield](https://storage.googleapis.com/scriptctf_challenges/Rev/Plastic-Shield/plastic-shield)

<details>

<summary>View Hint: Hint 1</summary>

The algorithm implementation itself is not the problem, I would look elsewhere.

</details>

<details>

<summary>strings plastic-shield, and you can have some good observation about the output</summary>

```shellscript
PTE1
H=PpA
ATSH
[A\]
ATSH
[A\]
@@H1
@HH1
/lib64/ld-linux-x86-64.so.2
free
putchar
strtol
strlen
malloc
__libc_start_main
sprintf
__isoc99_scanf
libc.so.6
GLIBC_2.7
GLIBC_2.34
GLIBC_2.2.5
__gmon_start__
Please enter the password: 
%255s
%02x
713d7f2c0f502f485a8af0c284bd3f1e7b03d27204a616a8340beaae23f130edf65401c1f99fe99f63486a385ccea217
Decrypted text: 
c|w{
9JLX
~=d]
lpHP
expand 32-byte k
1	,k
;*3$"
GCC: (GNU) 15.1.1 20250521 (Red Hat 15.1.1-2)
AV:4p1294
RV:running gcc 15.1.1 20250521
BV:annobin gcc 15.1.1 20250521
GW:0x7d60562 ../sysdeps/x86/abi-note.c
SP:3
SC:1
CF:8 ../sysdeps/x86/abi-note.c
FL:0 ../sysdeps/x86/abi-note.c
GA:1
PI:4
SE:0
iS:0
GW:0x7d60562 init.c
CF:8 init.c
FL:0 init.c
GW:0x7d60562 static-reloc.c
SP:0 static-reloc.c
CF:8 static-reloc.c
FL:0 static-reloc.c
crt1.o
__abi_tag
crtbegin.o
deregister_tm_clones
__do_global_dtors_aux
completed.0
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
plastic-shield.c
aes.c
rsbox
Rcon
KeyExpansion
AddRoundKey
xtime
InvMixColumns
InvSubBytes
InvShiftRows
InvCipher
XorWithIv
monocypher.c
load24_le
load32_le
load64_le
store32_le
store64_le
load32_le_buf
load64_le_buf
store32_le_buf
store64_le_buf
rotr64
rotl32
neq0
chacha20_rounds
chacha20_constant
poly_blocks
blake2b_compress
sigma.8
blake_update_32
blake_update_32_buf
copy_block
xor_block
extended_hash
g_rounds
fe_one
sqrtm1
lop_x
lop_y
ufactor
fe_0
fe_1
fe_copy
fe_neg
fe_add
fe_sub
fe_cswap
fe_ccopy
fe_frombytes_mask
fe_frombytes
fe_tobytes
fe_mul_small
fe_mul
fe_sq
fe_isodd
fe_isequal
invsqrt
fe_invert
scalar_bit
scalarmult
base_point.7
multiply
is_above_l
remove_l
mod_l
ge_zero
ge_tobytes
ge_frombytes_neg_vartime
ge_cache
ge_add
ge_sub
ge_madd
ge_msub
ge_double
b_window
slide_init
slide_step
zero_point.5
b_comb_low
b_comb_high
lookup_add
ge_scalarmult_base
half_ones.3
half_mod_L.4
hash_reduce
add_xl
dirty_base_point.2
select_lop
redc
Lm2.0
lock_auth
crtend.o
__FRAME_END__
_DYNAMIC
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
free@GLIBC_2.2.5
putchar@GLIBC_2.2.5
__libc_start_main@GLIBC_2.34
crypto_blake2b_keyed
crypto_verify16
crypto_x25519_dirty_fast
AES_CBC_encrypt_buffer
crypto_eddsa_reduce
crypto_aead_init_x
crypto_eddsa_sign
crypto_aead_write
crypto_argon2_no_extras
crypto_chacha20_h
_edata
crypto_chacha20_x
crypto_blake2b_init
AES_CBC_decrypt_buffer
crypto_blake2b_update
_fini
crypto_chacha20_ietf
strlen@GLIBC_2.2.5
crypto_verify64
crypto_poly1305_final
crypto_eddsa_scalarbase
AES_init_ctx_iv
crypto_elligator_map
AES_ECB_decrypt
AES_init_ctx
crypto_elligator_rev
crypto_chacha20_djb
crypto_x25519_dirty_small
AES_ctx_set_iv
crypto_x25519
__data_start
crypto_blake2b_keyed_init
crypto_blake2b_final
crypto_blake2b
crypto_elligator_key_pair
crypto_poly1305_init
AES_CTR_xcrypt_buffer
__gmon_start__
strtol@GLIBC_2.2.5
__dso_handle
_IO_stdin_used
crypto_poly1305_update
crypto_argon2
malloc@GLIBC_2.2.5
_end
_dl_relocate_static_pie
crypto_x25519_public_key
crypto_aead_init_ietf
crypto_aead_init_djb
crypto_eddsa_to_x25519
crypto_aead_lock
__bss_start
main
crypto_eddsa_trim_scalar
crypto_x25519_to_eddsa
crypto_poly1305
hex_to_bytes
__isoc99_scanf@GLIBC_2.7
crypto_eddsa_mul_add
crypto_eddsa_key_pair
crypto_verify32
sprintf@GLIBC_2.2.5
crypto_aead_read
__TMC_END__
crypto_x25519_inverse
crypto_eddsa_check
crypto_aead_unlock
AES_ECB_encrypt
crypto_eddsa_check_equation
crypto_wipe
.symtab
.strtab
.shstrtab
.note.gnu.build-id
.init
.text
.fini
.interp
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.rodata
.eh_frame_hdr
.eh_frame
.note.gnu.property
.note.ABI-tag
.init_array
.fini_array
.dynamic
.got
.got.plt
.data
.bss
.comment
.annobin.notes
.gnu.build.attributes

```

</details>

* This is after I throw it into dogbolt, and check the main of the program

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FOt9H6XHM09WSHOPV8c5d%2Fimage.png?alt=media&#x26;token=036aabfb-a3e9-4147-8fca-8b20db20cc88" alt=""><figcaption></figcaption></figure>

* Only one character is extracted: `char var_189 = var_148[rdx >> 2];`
* That character goes directly to blake2b: `crypto_blake2b(&var_188, 0x40, &var_189, 1);`

***

* Figedting some more then I have to look at Ghidra

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2F1e7nVUjzDekDXMcWlLRU%2Fimage.png?alt=media&#x26;token=ffb7cb0c-5862-4d0f-a8e6-ca7103fd8b7e" alt=""><figcaption></figcaption></figure>

* `0x3c` in hexadecimal = 60 in decimal
* So: `local_30 = (password_length * 60) / 100`
* Which simplifies to: `local_30 = password_length * 0.6`

With all that in places the binary `plastic-shield` is a password-checking program that:

1. Asks for a password input (up to 255 characters)
2. Applies a special character detection algorithm - it finds the character at position `floor(0.6 * password_length)`
3. Uses that special character as a key to decrypt an embedded ciphertext
4. Uses **BLAKE2b** hashing to derive a 64-byte hash from the special character
5. Uses **AES-CBC** decryption with:
   * Key: first 32 bytes of the hash
   * IV: bytes 32-48 of the hash
6. And we need to decrypts from the embedded hex string `713d7f2c0f502f485a8af0c284bd3f1e7b03d27204a616a8340beaae23f130edf65401c1f99fe99f63486a385ccea217`

{% hint style="info" %}
Script
{% endhint %}

```python
from binascii import unhexlify
from hashlib import blake2b
from Crypto.Cipher import AES


def main():
    # The embedded hex ciphertext from the binary
    hex_ciphertext = "713d7f2c0f502f485a8af0c284bd3f1e7b03d27204a616a8340beaae23f130edf65401c1f99fe99f63486a385ccea217"
    ciphertext = unhexlify(hex_ciphertext)

    print(f"[*] Brute forcing special character...")

    # Try all printable ASCII characters
    for i in range(32, 127):
        char = chr(i)

        # Hash the character with BLAKE2b (64 bytes)
        hash_result = blake2b(char.encode("utf-8"), digest_size=64).digest()

        # Split: first 32 bytes = key, next 16 bytes = IV
        key = hash_result[:32]
        iv = hash_result[32:48]

        # Decrypt with AES-CBC
        cipher = AES.new(key, AES.MODE_CBC, iv)
        plaintext = cipher.decrypt(ciphertext)

        # Remove PKCS7 padding
        pad_len = plaintext[-1]
        if 1 <= pad_len <= 16:
            plaintext = plaintext[:-pad_len]

        # Check if it looks like a flag
        decoded = plaintext.decode("utf-8", errors="ignore")
        if "scriptCTF{" in decoded:
            print(f"[+] Found special character: '{char}' (ASCII {i})")
            print(f"[+] Flag: {decoded}")

            # Generate example password
            password_length = 10
            special_pos = int(0.6 * password_length)  # Position 6 for length 10
            password = ["A"] * password_length
            password[special_pos] = char
            example_password = "".join(password)

            print(f"[+] Example working password: {example_password}")
            return

    print("[-] No flag found!")

main()

```

```bash
❯ python solve.py
[*] Brute forcing special character...
[+] Found special character: '`' (ASCII 96)
[+] Flag: scriptCTF{20_cau541i71e5_d3f3n5es_d0wn}
[+] Example working password: AAAAAA`AAA
```

* <mark style="color:blue;">`scriptCTF{20_cau541i71e5_d3f3n5es_d0wn}`</mark>

### Plastic Shield 2

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FVSzFsQkdAMCM5HghIIzx%2Fimage.png?alt=media&#x26;token=f316d93f-dabc-408f-a4d9-60817354ef2d" alt=""><figcaption></figcaption></figure>

> Okay! Fixed last time's issue. Seriously though, I swear this one is unbreakable.
>
> * [plastic-shield-2](https://storage.googleapis.com/scriptctf-wave2-randomchars1337/Rev/PlasticShield2/plastic-shield-2)

tbd, will write later.
