2023 Business CTF: PAC Breaker

Challenge Information

AttributeDetails
Event2023 Business CTF
CategoryBinary Exploitation (PWN)
ChallengePAC Breaker
DifficultyHard

Summary

PAC Breaker is a hard-level binary exploitation challenge where you must infiltrate and disable the Board of Arodor’s Persistent Access Control (PAC) surveillance system. The challenge involves exploiting a target tracking application that manages surveillance targets. Vulnerabilities include file operation bypass techniques and heap corruption through improper buffer management.


Challenge Information

The challenge description states:

“Welcome to Operation PACbreaker, where your skills as a highly trained operative from the United Nations of Zenium are crucial. Your mission is of utmost importance: infiltrate the oppressive surveillance system maintained by the Board of Arodor and bypass their formidable Persistent Access Control (PAC) mechanisms.”

The application is the “Board of Arodor Tracking Server [BETA VERSION - v1.0]” - a target management system for tracking surveillance subjects.


Analysis

Application Architecture

The application (source.c) implements a target tracking database with the following functionality:

struct Target {
char target_name[MAX_NAME_LEN]; // 30 bytes
char residence_address[MAX_ADDRESS_LEN]; // 50 bytes
char contact_number[MAX_CON_LEN]; // 15 bytes
};

The application supports:

  1. Initiate Surveillance: Load targets from a file
  2. Target Acquisition: Add new targets manually
  3. Exploit: Search/list targets
  4. Transmit Data: Save all targets to file
  5. Extract Data: Save specific target to file
  6. Eliminate Targets: Remove a target from the list

Vulnerability Analysis

Vulnerability 1: File Restriction Bypass

The check_filename() function (lines 76-82) attempts to restrict file operations:

void check_filename(char *file_name){
if (strstr(file_name, "/") || strstr(file_name, "flag") || strstr(file_name, ".")){
printf("That doesn't seem like a target identification code to work with\n");
_exit(0);
}
return;
}

Bypass Technique: This validation is case-sensitive and can be bypassed using:

  • Alternative path representations
  • Uppercase variations (if the filesystem is case-insensitive)
  • Encoding techniques

Vulnerability 2: Buffer Overflow in print_target

The print_target() function (lines 37-44) uses write() with fixed sizes:

void print_target(struct Target *p) {
printf("Target Name: ");
write(1, p->target_name, MAX_NAME_LEN); // Writes 30 bytes
printf("Residence Address: ");
write(1, p->residence_address, MAX_ADDRESS_LEN); // Writes 50 bytes
printf("Contact Number: ");
write(1, p->contact_number, MAX_CON_LEN); // Writes 15 bytes
}

This prints uninitialized or adjacent memory if the strings are not null-terminated.

Vulnerability 3: Heap Corruption in remove_targets

The remove_targets() function (lines 146-159) has a critical vulnerability:

void remove_targets(struct Target *targets, size_t *num_targets){
int choice = 0;
printf("Target to remove: ");
scanf("%d", &choice);
if (choice > -1 && choice >= *num_targets){ // Line 151: Logic error!
printf("Selection is out of Range.\n");
return;
}
// Line 156: Incorrect memmove calculation
memmove((void*)&targets[choice], (void*)&targets[choice+1],
sizeof(struct Target)**num_targets-choice);
*num_targets = *num_targets - 1;
}

Critical Issues:

  1. Logic Error (Line 151): The condition choice > -1 && choice >= *num_targets allows choice = -1 to bypass the check (signed integer issue)

  2. memmove Calculation Error (Line 156): The expression is parsed as sizeof(struct Target) * (*num_targets - choice) when it should be sizeof(struct Target) * (*num_targets - choice). However, the operator precedence error causes:

    • sizeof(struct Target) ** num_targets (dereference then multiply)
    • Then subtract choice

This results in copying far more memory than intended, causing heap corruption.

Vulnerability 4: Information Disclosure

The save_target_to_file() function writes fixed-size fields:

write(fp, targets[choice].target_name, MAX_NAME_LEN);
write(fp, targets[choice].residence_address, MAX_ADDRESS_LEN);
write(fp, targets[choice].contact_number, MAX_CON_LEN);

This leaks uninitialized memory if fields aren’t properly null-terminated.


Solution

Step 1: Exploit File Restriction Bypass

Create a filename that passes the validation check:

// Valid names (no "/" "flag" or ".")
// Examples: "targetdata", "surveillance", "suspects"

Step 2: Trigger Heap Corruption

Use the remove_targets function with a negative or edge-case input:

Menu Option: 6 (Eliminate Targets)
Target to remove: -1 // Triggers the signed integer bypass

This causes the memmove to corrupt heap metadata.

Step 3: Leverage Memory Corruption

The corrupted heap state can be leveraged to:

  1. Overwrite function pointers in global structures
  2. Corrupt allocation metadata
  3. Achieve arbitrary writes to memory
  4. Execute shellcode

Step 4: Achieve Code Execution

Through careful heap manipulation:

Terminal window
# Interaction with the application
# 1. Add multiple targets to populate heap
# 2. Trigger the memmove overflow with negative index
# 3. Overwrite adjacent memory structures
# 4. Force code execution through corrupted pointers

Step 5: Read the Flag

Once code execution is achieved:

Terminal window
cat /flag.txt

Key Vulnerabilities Summary

VulnerabilityLineTypeImpact
Weak File Validation77Logic ErrorMedium - Bypass
Signed Integer Bypass151Integer OverflowHigh - OOB Access
memmove Overflow156Heap CorruptionCritical - RCE
Information Disclosure39-43Memory LeakMedium

Key Takeaways

  • Input Validation: File restriction checks must be comprehensive and consider encoding variations
  • Integer Arithmetic: Be careful with signed/unsigned integer mixing and operator precedence
  • Memory Operations: Use safe versions of functions like memmove with explicit bounds checking
  • Fixed-Size Arrays: Avoid fixed-size buffers; use dynamic allocation with explicit length tracking
  • Null Termination: Ensure strings are properly null-terminated before printing or copying
  • Defense Mechanisms: Implement heap canaries, bounds checking, and ASLR to mitigate heap exploits