Added writeups

This commit is contained in:
m0rph3us1987
2026-03-08 12:22:39 +01:00
parent a566ea77d1
commit a79656b647
43 changed files with 6940 additions and 0 deletions

133
cryptoracle_v2.md Normal file
View File

@@ -0,0 +1,133 @@
# CryptOracle v2
`CryptOracle v2` is the "Hardened" version of the HSM simulator. The direct memory read vulnerability from v1 has been fixed, but a new "Cryptographic Engine" has been added. The goal is the same: dump the secret key from the secure memory region at `0x10000`.
## Information Gathering
After connecting to the server, we see a familiar interface with new commands like `enc` and `dec`.
```
CryptOracle v2.0 (Hardened!)
Setting up memory...
0x10000 - 0x11000 : Secure Memory (Keys/ROM)
0x20000 - 0x28000 : User Memory
Type 'help' for commands.
```
## Reverse Engineering
We open the binary in Ghidra and check the functions that have changed.
### 1. The Patch (`do_read`)
The `do_read` function now includes an explicit check that blocks any attempt to read from addresses below the user memory region.
```c
void do_read(uint32_t offset,uint32_t len)
{
uint8_t *data;
// This check prevents us from reading 0x10000 directly.
if (offset < 0x20000) {
puts("ERR_ACCESS_VIOLATION");
}
else {
// ... (rest of the function)
}
return;
}
```
The simple `rm 0x10000 32` from v1 will no longer work.
### 2. The Cryptographic Engine (`do_cipher`)
With the direct read vulnerability from v1 patched, we must now investigate other commands as a potential attack surface. The `enc` and `dec` commands, which were present before, now become our primary focus. They are handled by the `do_cipher` function. It allows encrypting or decrypting data from a source address to a destination address using a key stored in a secure "slot".
```c
void do_cipher(char mode, uint32_t src_off, uint32_t len, int slot, uint32_t dst_off)
{
// ...
// Get pointer to source buffer (can be anywhere)
src_ptr = get_ptr(src_off, len, 0);
// Get pointer to destination buffer (must be writable)
dst_ptr = get_ptr(dst_off, len, 1);
// Get pointer to the key from a secure slot
// Address is calculated as 0x10000 + slot * 32
key_ptr = get_ptr((slot + 0x800) * 0x20, 0x20, 0);
if (/* all pointers are valid */) {
// ... performs AES encryption/decryption block by block ...
}
}
```
The key insight is in how the pointers are validated, which all happens inside the `get_ptr` function.
### 3. Vulnerability Analysis (`get_ptr`)
Here is the decompiled `get_ptr` function from Ghidra. It takes an offset, a length, and a flag `is_write` that is `1` for write operations and `0` for read operations.
```c
uint8_t * get_ptr(uint32_t offset,uint32_t len,int is_write)
{
uint8_t *puVar1;
if (len + offset < offset) {
puVar1 = (uint8_t *)0x0;
}
else if ((offset < 0x10000) || (0x11000 < len + offset)) {
if ((offset < 0x20000) || (0x28000 < len + offset)) {
puVar1 = (uint8_t *)0x0;
}
else {
puVar1 = (uint8_t *)(ulong)offset;
}
}
else if ((is_write == 0) || (0x7ff < offset - 0x10000)) {
puVar1 = (uint8_t *)(ulong)offset;
}
else {
puVar1 = (uint8_t *)0x0;
}
return puVar1;
}
```
**The Vulnerability:**
The logic in the final `else if` block is flawed. Let's trace it for a read operation (`is_write == 0`) on the secure flag region (`offset = 0x10000`).
* The expression is `(is_write == 0) || (0x7ff < offset - 0x10000)`.
* Since `is_write` is `0`, the first part of the OR `(0 == 0)` is **true**.
* The entire expression becomes `true`, and access is granted, returning a valid pointer.
The check that should prevent writing to the first 2KB of secure memory (`0x7ff < offset - 0x10000`) is completely bypassed for any read operation. The `do_cipher` function abuses this by requesting a read (`is_write=0`) on the secure flag, which `get_ptr` allows. This creates a **Confused Deputy** scenario, where we use the oracle's legitimate read permissions to exfiltrate data.
## Solution
The attack is a two-step process:
1. **Encrypt**: Use the `enc` command to instruct the oracle to read from the secure flag region (`0x10000`) and write the encrypted result (ciphertext) into user-accessible memory (`0x20000`).
2. **Decrypt**: Use the `dec` command to instruct the oracle to read the ciphertext from user memory (`0x20000`) and write the decrypted result (plaintext) back into a different location in user memory (`0x20100`).
3. **Read**: Use the now-fixed `rm` command to read the plaintext flag from `0x20100`.
### Execution
```bash
# Step 1: Encrypt the flag from secure memory to user memory
> enc 0x10000 32 30 0x20000
OK
# Step 2: Decrypt the ciphertext from user memory to another user memory location
> dec 0x20000 32 30 0x20100
OK
# Step 3: Read the plaintext flag from user memory
> rm 0x20100 32
00020100: 7b 66 6c 61 67 3a 20 73 65 6c 66 5f 65 6e 63 72 {flag: self_encr
00020110: 79 70 74 69 6f 6e 5f 69 73 5f 6e 69 63 65 21 7d yption_is_nice!}
```
The flag is revealed: `{flag: self_encryption_is_nice!}`