cybersecurity · intermediate · ~15 min · safe pentest lab

Read a filename from a mock MFT record

Bounds-safe offset/length parsing of a record-style binary format.

Challenge

Read a filename out of a (mock) NTFS MFT record. The format is simplified, but the defensive shape — check the signature, bounds-check offsets, bounded-copy — is the same as the real thing.

Task

Implement int read_mft_name(const uint8_t *rec, size_t n, char *out, size_t cap) that copies the record's name into out.

Input

  • rec, n: a fixture record buffer and its length, baked into the harness. Layout:
    • bytes 0-3: signature 'F','I','L','E'
    • bytes 4-5: name_offset (u16 LE)
    • bytes 6-7: name_length (u16 LE)
    • the name is name_length ASCII bytes starting at rec[name_offset]
  • out, cap: the output buffer and its capacity.

Output

Returns int: the number of bytes written to out (excluding the NUL) on success, or -1 on failure.

Example

rec with signature FILE, name_offset 10, name_length 5, name "audit"
read_mft_name(rec, n, out, cap)   ->   out = "audit", returns 5

Edge cases

  • Returns -1 if any input is NULL, cap == 0, n < 8, the signature mismatches, name_offset + name_length walks past n, or the name would not fit in cap.

Rules

  • Read the two u16s with byte shifts.
  • Compute end = (size_t)name_offset + (size_t)name_length as size_t to avoid 16-bit overflow.
  • NUL-terminate the output.

Why this matters

Real MFT parsing is complex. The defensive shape — magic, bounds-checked offsets, bounded copy — is the same in the mock and the real format.

Input format

A byte buffer + its length, an output buffer + capacity.

Output format

Non-negative byte count, or -1 on any failure.

Constraints

Signature must match. Cast to size_t before adding. NUL-terminate output.

Starter code

#include <stdint.h>
#include <stddef.h>
int read_mft_name(const uint8_t *rec, size_t n, char *out, size_t cap) {
    /* TODO */
    (void)rec; (void)n; (void)out; (void)cap;
    return -1;
}

Common mistakes

Adding off + len as u16 (overflows). Forgetting that len == 0 is a legal empty name. Reading rec[4..7] when n < 8.

Edge cases to handle

Name length 0. Offset right at the end of the buffer. NULL inputs.

Complexity

O(len) per call.

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.