cybersecurity · intermediate · ~15 min · safe pentest lab

Parse a MAC Address Safely

Validate the full structure of attacker-controlled fixed-format input character-by-character before consuming it, rejecting anything that does not match exactly instead of assuming well-formed data.

Challenge

A tool ingests MAC addresses from untrusted sources (ARP tables, config files, packet fields) and copies them into a fixed 6-byte buffer used for filtering and lookups. The insecure assumption is that any string handed in is a well-formed aa:bb:cc:dd:ee:ff. If you trust that, a malformed input like a single-digit group, a wrong separator, or a truncated string lets you read past the string or write bytes you never validated, corrupting the ARP/filter table.

Your job is to parse defensively: accept ONLY the exact shape (6 groups of exactly two hex digits, lowercase or uppercase, separated by exactly five colons, then a terminating NUL) and write the 6 bytes into out. Anything else is rejected with -1 and out is not trusted. Deny by default; validate every character position BEFORE using it. The buffer is baked into the harness — this never touches a live host or network.

Example

Given out of length 6: parse_mac("00:00:00:00:00:00", out) -> 0 and parse_mac("aa-bb-cc-dd-ee-ff", out) -> -1.

Input format

A NUL-terminated C string s (attacker-controlled) and a caller-provided 6-byte array out.

Output format

Returns int: 0 on success (out[0..5] filled), -1 if the string is malformed in any way.

Constraints

A valid MAC is exactly 17 characters: 6 two-hex-digit groups joined by 5 colons. Hex digits may be 0-9, a-f, or A-F. No leading/trailing whitespace, no other separators, no shorter/longer groups. Do not read or write out of bounds for any input, including NULL.

Starter code

int parse_mac(const char *s, unsigned char out[6]){
    /* TODO: parse the MAC address into out[0..5].
       Reject any malformed input with -1. This stub does neither. */
    (void)s; (void)out;
    return 0;
}

Common mistakes

Using sscanf("%x:%x:...") which accepts single-digit groups, wrong widths, and trailing garbage; not checking that exactly 5 colons and a NUL appear at the right positions; reading s[i] before confirming the string is long enough; forgetting to reject when extra characters follow the 6th group; not handling NULL.

Edge cases to handle

Empty string; NULL pointer; too few groups (truncated); too many groups (extra trailing group); single-digit group like a:b:c:d:e:f; wrong separator such as dashes; non-hex characters like g or z; trailing junk after an otherwise-valid MAC; all-zero and all-FF boundary values.

Background lessons

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