Krotate
Event: UNbreakable (teams) 2024 | Difficulty: Medium | Points: 370 | Solves: 13 |
What we know
We are provided by the challenge with 3 files:
- chall.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-----BEGIN PGP SIGNATURE-----
iQGzBAEBCgAdFiEEzPHvlUeruVX0heb1tpW1DotF5QYFAmWo5oMACgkQtpW1DotF
5QY62wwAudnaWyEAHCzLfhoqGRacozcmhagBr+HlPhEOApd6lwIZ01At+Q4Yj5z2
IYk2kpdxe6fZ5pZZoGyMk5TrNQaeHKn+w9hKdNsaQTZSPSgXT9pQ1FyiaYe5tKEf
Zs9g4k+mEbK7uJpVfCBfvMnxiARxyNzvTs4/EEP0/KGxwpuWIrU8Xwz51gZFNJgr
3cjeV6esIxyAoPHSpzvGwC2YA3unsSh9bWS6BjtmOs2As1YC7asbO0dRANcjz//0
mYDAXM1W68ASrHT22COCpv+r5QBD2tPiKrjdMSYGkSXfWsTAf+bfu5VM/nGUKD/n
gShplAr2yLdwWkz6UTMboMZRMK5UfjzumX99ICO3hYL0mU3QQXyFnkXtR0ygcGOy
Xke5v/1O4iNmwmn0G/xBF4s2kfeh9DOFyBJeHtgMuNVXVkZOe2FVDecK9UOR4/7h
Z63mLMvOhlniIcy5HrIUXfz0HQAgVGye7jgDvBJCS9Y2dc+5mcHraFj+FEfL8QIR
K7XNR2Tf
=pum0
-----END PGP SIGNATURE-----
##Summary
I used the given PGP signature to find the key used on the last block*. From the last block up, I regenerate the R at that step, use it to find the key at that step and then decrypt the respective block with the proper key.
- Plaintext is split into blocks of 100 characters:
1
2
KEY_LEN = 100
blocks = [text[i : i + KEY_LEN] for i in range(0, len(text), KEY_LEN)]
##Matching the blocks
I kept the original functions from the given code: RGEN(), xor_text() and next_key(). The length of ciphertext was not divisible by 100, so I cut the remainder part out and handled the last complete block. Then I also trimmed the PGP signature to match that exact block.
Here is how:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ciphertext = b""
with open("ciphertext.txt", "rb") as f:
ciphertext = f.read()
pgp = ""
with open("pgpsgn.txt", "r") as f: # PGP signature
pgp = f.read()
# ignore the last chunk (of length < 100)
len_remainder = len(ciphertext) % 100
ciphertext = ciphertext[:-len_remainder]
#trim pgp signature to match
pgplength = len(pgp)
pgp = pgp[(pgplength len_remainder 99): (pgplength len_remainder + 1)]
pgp bytes(pgp, 'utf-8')
##Finding the key
Now, we have the original and the encrypted versions of the last block of length 100. These xor’ed together will produce the last key, which can be used to obtain all the other keys.
1
2
# create key for the last block
key = xor_text(ciphertext[-100:), pgp)
##Bottoms up!
From the last chunk to the first, we xor it with the current key (initially, that is the last key: found previously for the last block).
From the current key, we make the previous key: by regenerating the R with 100 less calls for RGEN(). Then, we reunite the decrypted chunks to print the whole raw message.
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
# functions from the original code
ciphertext = b""
with open("ciphertext.txt", "rb") as f:
ciphertext = f.read()
pgp = ""
with open("pgpsgn.txt", "r") as f: # PGP signature
pgp = f.read()
# ignore the last chunk (of length < 100)
len_remainder = len(ciphertext) % 100
ciphertext = ciphertext[:-len_remainder]
# trim pgp signature to match
pgplength = len(pgp)
pgp = pgp[(pgplength - len_remainder - 99): (pgplength - len_remainder + 1)]
pgp = bytes(pgp, 'utf-8')
# create key for the last block
key = xor_text(ciphertext[-100:], pgp)
raw = ""
for i in range(29):
# prepend decrypted chunk
raw = (xor_text(ciphertext[-100 * (i + 1):len(ciphertext) - i * 100], key)).decode() + raw
# regenerate R for previous key
R = 0x01
for j in range(2800 - (i + 1) * 100):
RGEN()
key = next_key(key)
# print final message
raw += "D PGP SIGNATURE-----"
print(raw)
Spoiler! This is the decrypted output:
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
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
URGENT COMMUNICATION
To all personnel and key stakeholders,
I write to you under pressing circumstances that demand our immediate attention and swift collective action. Our critical systems, the very lifeblood of our operations, are facing an imminent threat that requires the utmost urgency in our response.
As the hands of the clock move inexorably forward, our window of opportunity to secure these systems narrows. The potential consequences of inaction are severe, and we cannot afford to underestimate the gravity of the situation.
Each member of our organization is a crucial component in this endeavor. I implore you to mobilize with speed and purpose, drawing upon your unique skills and expertise. The seamless coordination of our efforts is paramount in the face of this impending challenge.
It is incumbent upon us to fortify our defenses and implement contingency plans to ensure the resilience of our critical infrastructure. Time is not a luxury we possess; therefore, every action taken must be deliberate, calculated, and aligned with our overarching mission.
In this pivotal moment, let us rise above the immediate threat and showcase the strength of our collective resolve. The success of our organization hinges on the efficacy of our response to this crisis. Failure to act decisively is not an option, as the consequences could reverberate far beyond our immediate sphere.
Consider this an urgent call to arms, a rallying cry for unity in purpose. We face adversity, but through our combined efforts, we can overcome it. Let us navigate these turbulent waters with a shared commitment to excellence and an unwavering dedication to the security of our critical systems.
As you embark on this mission, know that your contributions matter, and they form an integral part of the shield we are erecting to protect our organization's future. May our actions today echo with the assurance that we met the challenge head-on and emerged stronger.
Go forth with determination, resilience, and the unwavering belief that together, we shall secure the future of our critical systems.
The secret code to our systems is: CTF{cc64393474865290892e5197153ad6109151d8ee2fd5e316d81b80c3d825bd82}
Godspeed.
-----BEGIN PGP SIGNATURE-----
iQGzBAEBCgAdFiEEzPHvlUeruVX0heb1tpW1DotF5QYFAmWo5oMACgkQtpW1DotF
5QY62wwAudnaWyEAHCzLfhoqGRacozcmhagBr+HlPhEOApd6lwIZ01At+Q4Yj5z2
IYk2kpdxe6fZ5pZZoGyMk5TrNQaeHKn+w9hKdNsaQTZSPSgXT9pQ1FyiaYe5tKEf
Zs9g4k+mEbK7uJpVfCBfvMnxiARxyNzvTs4/EEP0/KGxwpuWIrU8Xwz51gZFNJgr
3cjeV6esIxyAoPHSpzvGwC2YA3unsSh9bWS6BjtmOs2As1YC7asbO0dRANcjz//0
mYDAXM1W68ASrHT22COCpv+r5QBD2tPiKrjdMSYGkSXfWsTAf+bfu5VM/nGUKD/n
gShplAr2yLdwWkz6UTMboMZRMK5UfjzumX99ICO3hYL0mU3QQXyFnkXtR0ygcGOy
Xke5v/1O4iNmwmn0G/xBF4s2kfeh9DOFyBJeHtgMuNVXVkZOe2FVDecK9UOR4/7h
Z63mLMvOhlniIcy5HrIUXfz0HQAgVGye7jgDvBJCS9Y2dc+5mcHraFj+FEfL8QIR
K7XNR2Tf
=pum0
-----END PGP SIGNATURE-----