Hacking
Writeups
Crypto
Foil the Plot

Foil the Plot

Description

CTF: Whitehacks 2022

Author: Chun

Difficulty: Hard

APOCALYPSE activated a sleeper cell for a suicide bombing but the target location is not known.....

Experts from CSIT have discovered the attacker-controlled server that was used to send a secret message to the sleeper cell. The server is protected with a password that is at least 40 chars long! The server does not store the password but to our good fortune, a weakness has been discovered in the way it performs the authentication.

It validates the password by performing the following steps:

  1. Split the 40 char password into 2 equally-sized segments
  2. Check that the segments are not identical
  3. Generate the SHA-256 digests of both segments
  4. Check that the last 5 bytes of both digests are identical

Your task is to gain authentication to the server, decipher the message and determine the target location before it's too late!

Challenge Access:
http://challenges1.whitehacks.xyz:28800 (opens in a new tab) http://challenges2.whitehacks.xyz:28800 (opens in a new tab)

Enter the flag as WH2022{ID_postal code}

Eg. WH2022{s@m_pl3_123456}

Solution

Pwned by @skytect (opens in a new tab)

After visiting the site, one encounters a sign in page that requires a password.

  1. Split the 40 char password into 2 equally-sized segments
  2. Check that the segments are not identical
  3. Generate the SHA-256 digests of both segments
  4. Check that the last 5 bytes of both digests are identical

Looking at this, we can probably generate a working password by brute-force by finding a valid hash collision. Here's the script I used:

from hashlib import sha256
from itertools import product
from string import ascii_lowercase
 
endings = {}
 
for i, s in enumerate(product(ascii_lowercase, repeat = 20)):
    s = ''.join(s)
    h = sha256(s.encode()).hexdigest()
    ending = h[-10:]
 
    if ending in endings.keys():
        print(s, h)
        print(endings[ending][0], endings[ending][1])
        break
    else:
        endings[ending] = (s, h)
 
    if i % 1000000 == 0:
        print(f'Checked until {s}')

It can yield a match within 2 seconds on my computer:

aaaaaaaaaaaaaaachlhe acfaaf03622106a652c4d7a3b7d5703161c0ea0fbe15a7fc75f31fa68ebcad86
aaaaaaaaaaaaaaacgxur 957c4c3f3435548089a5f70d76a7331a2a47773e138d55e4c00bf7a68ebcad86

If we use the password aaaaaaaaaaaaaaachlheaaaaaaaaaaaaaaacgxur, we're able to get past the authentication page.

On the site, we find the string:

UExBSU5URVhUIDw9PT4gKEFFUy1DQkMsIFNIQS0yNTYoMXN0IHNlZ21lbnQpLCBTSEEtMjU2KDJuZCBzZWdtZW50KSkgPD09PiBDSVBIRVJURVhU

After decoding it from Base64, we get:

PLAINTEXT <==> (AES-CBC, SHA-256(1st segment), SHA-256(2nd segment)) <==> CIPHERTEXT

This gives us a clue on how to deal with the other Base64 string hidden on the site:

W4+OWR0rcN2cclkxSIWJBC0pYQMFZXbePsW+GrJFj6gfRNV1lXy6y3hUKhI8M2Tulm4RW9RZnWKlNt/ZpTfaB82Irx5wnYdg4kilZIDzAB9HNk+5hnqgqam/uhqbixIbOT8OxeRsQZ8pd16qMg+v/A==

First, let's generate the SHA-256 hashes of our passcode's components:

aaaaaaaaaaaaaaachlhe acfaaf03622106a652c4d7a3b7d5703161c0ea0fbe15a7fc75f31fa68ebcad86
aaaaaaaaaaaaaaacgxur 957c4c3f3435548089a5f70d76a7331a2a47773e138d55e4c00bf7a68ebcad86

Then, we can use the following values to attempt to decrypt the AES-CBC on CyberChef (opens in a new tab):

Key: acfaaf03622106a652c4d7a3b7d5703161c0ea0fbe15a7fc75f31fa68ebcad86
IV : 957c4c3f3435548089a5f70d76a7331 (only the first half since an IV is 16 bytes)

Output:

[ID: h@$h_c011i?i0n] It is a tiger. It is also a leopard. It is the route to a chilling glimpse of hell.

We've now gotten the first part of the flag: h@$h_c011i?i0n.

The back portion gives us a hint to where the target location is.

It is a tiger. It is also a leopard. It is the route to a chilling glimpse of hell.

If you google the string, you would find Haw Par Villa, for which the postal code is 118628.

When we try those together, it works!

WH2022{h@$h_c011i$i0n_118628}