- Passing corrupted ciphertext to get the symmetric key leak
- Fastbin link corruption
- Exploiting double free and UAF in the heap
Challenge points: 964
No. of solves: 10
Challenge author: rudyerudite
The description for this challenge says,
Sail through Hade’s abode with your double-edged sword!
Further, the challenge was developed and tested on an environment with
OpenSSL1.0.2g for encryption functionality. In the following writeup, we will reference the functions used for encryption as
Enc(plaintext) and decryption function as
Before getting our hands dirty, executing
checksec tells us about the mitigations enabled in the binary:
Canary : Yes
The challenge performs the function of encrypting the user’s input and storing the ciphertext in user-allocated heap chunks (option 1) and deletes them on the user’s request (option 3). A user can allocate a maximum of 9 chunks.
The player can store a plaintext on the .bss section and modify it later by sending the ciphertext (option 2). The key and the IV used for
AES-CBC encryption are stored in the .bss section. The IV is generated randomly and a static key used (read from a file) in every session.
Deletion of a chunk causes a
double-free and also there exists a
UAF which can help us to get the
libc leaks easily by freeing, allocating, and reading the same Unsorted Bin chunk.
To overwrite the pointer the attacker must get the
symmetric key used in the block cipher otherwise the encryption functionality would corrupt the user’s payload when storing it in memory. For getting a way out of this we need
symmetric key leaks.
Now we will use option 3 here. As the binary prints the name we can leak the key too! For that we need to bypass the
remove_padding function. Why? Check out the snippet:
To avoid the replacement with NULL bytes, the attacker must craft a ciphertext payload such that the last byte of the decrypted ciphertext is a negative number. In doing so, the naive padding function does not operate correctly (retaining the padded bytes). The intended way for this was to use the CBC bit-flipping attack to modify the last byte of the initial ciphertext (Encrypted code). This leads to leaking out the
symmetric key as there is no null-byte termination for the naive
After leaking our the key, the attacker must send the Dec(payload) and use the given IV and leaked key for the operation. As,
Enc(Dec(PT)) == Dec(Enc(PT)) we can now craftily pass our input such that the intended payload is not corrupted by the encryption function.
After this, the player can use the double free and overwrite the forward pointer of the fastbin chunk with a pointer near
__malloc_hook such that the next pointer points to value
0x7F (satisfying the size check of fastbin). A detailed explanation for the fastbin corruption attack can be found here. Mind you, the fake address or the attack payload must be sent to the binary as
Dec(Fake_addr_payload). The content is then stored as
Enc(Dec(Fake_addr_payload)) which is
Fake_addr_payload in the heap chunk.
We can get a chunk allocated at this address after invoking a couple of
malloc() functions. We can then overwrite
__malloc_hook with a gadget that executes
system() on the next allocation.
from pwn import *