cybersecurity · beginner · ~15 min · safe pentest lab
Recognize the special Unix permission bits that enable local privilege escalation (setuid/setgid/world-writable) and test for them safely with bitmasks, without assuming a superficially normal mode is harmless.
On Linux, a file's mode carries special permission bits that a privilege-escalation attacker loves to find. A setuid binary (04000) runs with the file owner's identity — a setuid-root program is a classic escalation path. A setgid binary (02000) runs with the file's group. A world-writable file (00002) lets any local user rewrite its contents, which can hijack scripts, configs, or a Docker mount.
You are writing the core check for an offline auditor. The harness bakes a fixed array of file modes into memory (no live filesystem, no network, no target). Your job is purely arithmetic on the bits handed to you.
Implement:
int is_dangerous_mode(unsigned mode);
Return 1 if any of these bits is set: setuid (04000), setgid (02000), or world-writable (00002). Otherwise return 0. The insecure assumption to avoid is treating an ordinary-looking mode like 0755 as safe while ignoring an added setuid bit that turns it into 04755.
0000 and other benign modes (e.g. 0644, 0755) are safe -> return 0.01000 alone is not in scope and must return 0.06755) is dangerous, as is an all-ones mode 0xFFFFFFFF.A single unsigned integer mode holding Unix permission bits (octal), taken from a fixed in-harness array. No I/O; the value is passed as the function argument.
Return an int: 1 if the mode has setuid, setgid, or world-writable set; 0 otherwise.
C11, freestanding logic (no syscalls, no filesystem, no allocation). mode may be any value in 0 .. 0xFFFFFFFF. Test only the three bits in scope: 04000, 02000, 00002. Do not treat sticky (01000) or any other bit as dangerous. Constant-time bit checks only.
int is_dangerous_mode(unsigned mode){
/* TODO: audit the permission bits. Deny by default is NOT enough here —
you must actually detect setuid (04000), setgid (02000), and
world-writable (00002). Return 1 if any is set, else 0. */
(void)mode;
return -1; /* placeholder: not a valid answer */
}Using logical AND (&&) instead of bitwise AND (&); comparing mode == 04000 (exact equality) instead of masking, which misses combined modes like 04755; forgetting the world-writable bit and only checking setuid/setgid; returning the masked value directly (which can be a non-1 truthy number) when the contract asks for exactly 0 or 1; confusing the sticky bit 01000 with a dangerous bit.
mode 0 (no bits) -> 0; benign 0644 and 0755 -> 0; sticky-only 01000 -> 0 (out of scope, must be rejected as non-dangerous); world-writable-only 00002 -> 1; setuid+setgid combos like 06755 -> 1; all-ones 0xFFFFFFFF -> 1.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.