LEARN SECURE C AND EXPLOIT AWARENESS
C gives you powerโand with that power comes the responsibility to not shoot yourself (or your users) in the foot. Most critical vulnerabilities in operating systems, browsers, and infrastructure are C memory corruption bugs.
Learn Secure C Programming & Exploit Awareness: From Vulnerable Code to Bulletproof Defense
Goal: Deeply understand secure coding practices in Cโfrom bounds checking and integer overflow defense to understanding the very exploits youโre defending against (stack smashing, heap exploitation, format strings).
Why Learn Secure C Programming?
C gives you powerโand with that power comes the responsibility to not shoot yourself (or your users) in the foot. Most critical vulnerabilities in operating systems, browsers, and infrastructure are C memory corruption bugs.
After completing these projects, you will:
- Write C code that resists buffer overflows, integer overflows, and format string attacks
- Understand exactly how attackers exploit vulnerable code
- Choose safe APIs over dangerous legacy functions
- Audit code for security vulnerabilities
- Think like both a defender and an attacker
- Build tools that detect and prevent security issues
Core Concept Analysis
The Security Landscape in C
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ VULNERABLE C CODE โ
โ โ
โ char buf[64]; โ
โ gets(buf); // No bounds checking! โ
โ printf(buf); // Format string vuln! โ
โ int size = len * 4; // Integer overflow! โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโ
โผ โผ โผ
โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ STACK SMASHING โ โ HEAP EXPLOITATIONโ โ FORMAT STRING โ
โ โ โ โ โ โ
โ โข Buffer overflowโ โ โข Use-after-free โ โ โข %n writes โ
โ โข Return address โ โ โข Heap overflow โ โ โข %x info leak โ
โ โข ROP chains โ โ โข Double free โ โ โข Arbitrary R/W โ
โ โข Stack canary โ โ โข Chunk metadata โ โ โข GOT overwrite โ
โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ SECURE CODING PRACTICES โ
โ โ
โ โข Bounds checking (strncpy, snprintf, strlcpy) โ
โ โข Integer overflow defense (safe arithmetic) โ
โ โข Safe APIs vs legacy (fgets vs gets) โ
โ โข Input validation โ
โ โข Defense in depth โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Key Concepts Explained
1. Bounds Checking
The #1 cause of security vulnerabilities in C: writing past the end of buffers.
The Problem
char buffer[64];
strcpy(buffer, user_input); // What if user_input is 200 bytes?
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ buffer[64] โ โโโoverflowโโโโโโโโบ โ Return Addr โ CORRUPTED!
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
Safe Alternatives
| Dangerous Function | Safe Alternative | Notes |
|---|---|---|
gets(buf) |
fgets(buf, size, stdin) |
Always specify size |
strcpy(dst, src) |
strncpy(dst, src, n) |
NUL-termination issue! |
strcat(dst, src) |
strncat(dst, src, n) |
n = remaining space |
sprintf(buf, fmt) |
snprintf(buf, n, fmt) |
Returns chars needed |
scanf("%s", buf) |
scanf("%63s", buf) |
Width specifier |
The strncpy Trap
// WRONG: strncpy doesn't guarantee NUL termination!
char dest[10];
strncpy(dest, "This is a very long string", 10);
// dest is NOT NUL-terminated!
// CORRECT: Always ensure NUL termination
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';
// BETTER: Use strlcpy (BSD) or write your own
size_t strlcpy(char *dst, const char *src, size_t size);
2. Integer Overflow Defense
When arithmetic wraps around, bad things happen.
The Problem
// Unsigned overflow wraps around
unsigned int a = UINT_MAX; // 4294967295
unsigned int b = a + 1; // 0 (wrapped!)
// Size calculation overflow
size_t count = 1000000000;
size_t size = 4;
size_t total = count * size; // Overflow! Allocates tiny buffer
void *buf = malloc(total); // Allocates wrong amount
memcpy(buf, data, count * 4); // Massive overflow!
Safe Arithmetic Patterns
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ SAFE MULTIPLICATION โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ if (a != 0 && b > SIZE_MAX / a) { โ
โ // Overflow would occur โ
โ return ERROR; โ
โ } โ
โ result = a * b; // Safe now โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ SAFE ADDITION โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ if (a > SIZE_MAX - b) { โ
โ // Overflow would occur โ
โ return ERROR; โ
โ } โ
โ result = a + b; // Safe now โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
3. Safe APIs vs Legacy APIs
The Hall of Shame (Never Use)
// NEVER USE THESE
gets(buf); // No bounds check AT ALL - removed in C11!
sprintf(buf, fmt, ...); // No bounds check
strcpy(dst, src); // No bounds check
strcat(dst, src); // No bounds check
scanf("%s", buf); // No bounds check
vsprintf(); // No bounds check
The Safe Replacements
// ALWAYS USE THESE
fgets(buf, sizeof(buf), stdin); // Bounds-checked input
snprintf(buf, sizeof(buf), fmt, ...); // Bounds-checked format
strncpy(dst, src, sizeof(dst)); // Size-limited (careful!)
strlcpy(dst, src, sizeof(dst)); // BSD safe copy
strlcat(dst, src, sizeof(dst)); // BSD safe concat
scanf("%63s", buf); // Width-limited
4. Stack Smashing (Buffer Overflow on Stack)
Memory Layout During Overflow
Normal Stack Frame:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Return Address โ โ Saved by CALL
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Saved RBP โ โ Function prologue
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Canary Value โ โ Stack protector
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Local Variables โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Buffer[64] โ โ User input here
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
After Overflow:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AAAA (attacker address) โ โ Hijacked!
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ AAAA โ โ Overwritten
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ AAAA โ โ Canary corrupted!
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ AAAA โ โ Overwritten
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ AAAAAAAAAA... โ โ Overflow starts
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Modern Defenses
| Defense | What It Does | How Attackers Bypass |
|---|---|---|
| Stack Canary | Random value before return addr; checked on return | Info leak to discover value |
| ASLR | Randomize memory layout | Info leak + partial overwrite |
| NX/DEP | Stack not executable | ROP (return-oriented programming) |
| PIE | Randomize code addresses | Info leak |
5. Heap Exploitation
The heap is more complex than the stackโand so are its vulnerabilities.
Heap Memory Layout (glibc malloc)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ALLOCATED CHUNK โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ prev_size (8 bytes) โ size (8 bytes) โ
โ (if prev is free) โ includes flags (P,M,A) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ USER DATA โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ FREE CHUNK โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ prev_size (8 bytes) โ size (8 bytes) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ fd (forward ptr) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ bk (backward ptr) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ (unused space) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Common Heap Vulnerabilities
1. USE-AFTER-FREE
free(ptr);
// ... ptr used again without reassignment ...
ptr->data = value; // Writing to freed memory!
2. DOUBLE FREE
free(ptr);
free(ptr); // Corrupts heap metadata!
3. HEAP OVERFLOW
char *buf = malloc(64);
strcpy(buf, long_string); // Overwrites next chunk's metadata!
4. NULL POINTER DEREFERENCE
char *ptr = malloc(size);
// Forgot to check if ptr == NULL
*ptr = 'A'; // Crash or exploit on some systems
6. Format String Vulnerabilities
One of the most dangerous and underappreciated vulnerability classes.
The Problem
char *user_input = "%x %x %x %x %n";
printf(user_input); // NEVER DO THIS!
// What happens:
// %x - reads values from stack (info leak)
// %n - WRITES number of chars printed to address on stack!
Format String Powers
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Format Specifier โ What It Does โ
โโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ %x โ Read 4 bytes from stack (hex) โ
โ %lx โ Read 8 bytes from stack (hex) โ
โ %s โ Read string from address on stack โ
โ %n โ WRITE count of chars to address! โ
โ %hn โ Write 2 bytes (short) โ
โ %hhn โ Write 1 byte โ
โ %7$x โ Direct parameter access (7th arg) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Attack Example:
printf(user_input);
If user_input = "%x.%x.%x.%x"
Output: deadbeef.cafebabe.12345678.87654321
^^^^^^^^ ^^^^^^^^ ^^^^^^^^ ^^^^^^^^
Stack values leaked!
If user_input = "AAAA%7$n"
Writes 4 (length of "AAAA") to address 0x41414141!
Project List
The following 15 projects will teach you secure C programming from defensive techniques to understanding attacker methodologies.
Project 1: Safe String Library
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: Rust, Go
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 4. The โOpen Coreโ Infrastructure
- Difficulty: Level 2: Intermediate
- Knowledge Area: Secure Coding / String Handling
- Software or Tool: GCC, Valgrind, AddressSanitizer
- Main Book: โEffective C, 2nd Editionโ by Robert C. Seacord
What youโll build: A complete safe string library implementing strlcpy(), strlcat(), safe snprintf() wrappers, and bounded string operations that prevent buffer overflows.
Why it teaches secure coding: Strings are the #1 source of buffer overflows in C. Building your own safe library forces you to understand exactly why strcpy() is dangerous and how to prevent overflows.
Core challenges youโll face:
- Handling edge cases โ maps to empty strings, NULL pointers, zero-length buffers
- Ensuring NUL termination โ maps to strncpy doesnโt guarantee it
- Calculating remaining space โ maps to preventing off-by-one errors
- Return value design โ maps to detecting truncation
Resources for key challenges:
- โEffective C, 2nd Editionโ Chapter 5 - Strings and arrays
- OpenBSD strlcpy/strlcat man pages - The reference implementation
- CERT C Secure Coding Standard - STR07-C through STR38-C
Key Concepts:
- String Representation in C: โC Programming: A Modern Approachโ Ch. 13 - K.N. King
- Buffer Overflow Prevention: โEffective C, 2nd Editionโ Ch. 5 - Seacord
- Safe String Functions: OpenBSD strlcpy(3) man page
Difficulty: Intermediate Time estimate: 1 week Prerequisites: Understanding of C pointers, arrays, and memory layout
Real world outcome:
$ ./test_safestring
Testing safe_strlcpy...
โ Normal copy: "Hello" -> "Hello"
โ Truncation: "Very long string" -> "Very lon" (truncated, returns 16)
โ Zero-length buffer: Returns strlen(src), no write
โ NULL source: Returns 0, dest unchanged
Testing safe_strlcat...
โ Normal concat: "Hello" + " World" -> "Hello World"
โ Truncation: Properly truncated, returns total needed
โ Full buffer: No overflow, returns needed length
Testing safe_snprintf wrapper...
โ Format string attacks blocked
โ Truncation detected: snprintf_safe returned -1
โ Always NUL-terminated
All 15 tests passed!
Implementation Hints:
Key design decisions for safe_strlcpy():
-
Return value: Return the total length of the string that WOULD have been created (like OpenBSD strlcpy). This lets callers detect truncation:
if (strlcpy(dst, src, size) >= size) { /* truncated */ } - Edge cases to handle:
- What if
sizeis 0? (Donโt write anything, return strlen(src)) - What if
srcis NULL? (Define behavior: return 0? crash? assert?) - What if
dstis NULL? (Only valid if size is 0)
- What if
- NUL termination guarantee: Unlike
strncpy(), ALWAYS NUL-terminate (when size > 0)
Questions to guide implementation:
- How does
strncpy()fail to be safe? (Hint: no NUL termination when src >= n) - Why is the return value important for security?
- Whatโs the difference between
strlcpy()andsnprintf("%s", ...)? - How would you handle multi-byte (UTF-8) strings?
Learning milestones:
- Implement strlcpy/strlcat โ Understand size-limited string operations
- Handle all edge cases โ Build robust code
- Create snprintf wrapper โ Detect truncation automatically
- Write comprehensive tests โ Prove correctness
Project 2: Integer Overflow Detection Library
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: Rust (has built-in!), C++
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 3. The โService & Supportโ Model
- Difficulty: Level 2: Intermediate
- Knowledge Area: Secure Coding / Arithmetic Safety
- Software or Tool: GCC builtins, UBSan
- Main Book: โSecure Coding in C and C++โ by Robert C. Seacord
What youโll build: A library of safe arithmetic functions that detect and prevent integer overflow for addition, subtraction, multiplication, and division across all integer types.
Why it teaches secure coding: Integer overflows cause malloc() to allocate tiny buffers, loop counters to wrap around, and size calculations to become negativeโall leading to exploitable vulnerabilities.
Core challenges youโll face:
- Detecting overflow before it happens โ maps to pre-check patterns
- Handling signed vs unsigned โ maps to different overflow behavior
- Type width differences โ maps to int, long, size_t variations
- Performance considerations โ maps to compiler builtins vs manual checks
Resources for key challenges:
- โSecure Coding in C and C++โ Chapter 5 - Integer Security
- GCC __builtin_add_overflow documentation
- CERT C: INT30-C through INT36-C
Key Concepts:
- Twoโs Complement Arithmetic: โComputer Systems: A Programmerโs Perspectiveโ Ch. 2
- Integer Overflow Patterns: CERT C INT32-C
- Safe Integer Libraries: SafeInt library documentation
Difficulty: Intermediate Time estimate: 1 week Prerequisites: Understanding of integer representation, twoโs complement
Real world outcome:
$ ./test_safe_math
Testing safe_add_size_t...
โ 1000 + 2000 = 3000 (no overflow)
โ SIZE_MAX + 1 = OVERFLOW DETECTED
โ SIZE_MAX/2 + SIZE_MAX/2 = SIZE_MAX-1 (no overflow)
Testing safe_mul_size_t...
โ 1000 * 1000 = 1000000 (no overflow)
โ SIZE_MAX * 2 = OVERFLOW DETECTED
โ 1000000000 * 5 = OVERFLOW DETECTED (on 32-bit size_t)
Testing safe_alloc_array...
โ alloc_array(1000000, 4) detected overflow, returned NULL
โ alloc_array(1000, 4) = 4000 bytes allocated
Testing CVE simulation...
Simulating CVE-2021-XXXX (count * element_size overflow)
โ Vulnerable code: Allocates 64 bytes, copies 4GB!
โ Safe code: Detects overflow, returns error
All tests passed!
Implementation Hints:
Two approaches:
Approach 1: Manual Pre-Checks
// For unsigned addition: check if result would wrap
// if a + b would overflow, then b > MAX - a
bool safe_add_size_t(size_t a, size_t b, size_t *result) {
if (b > SIZE_MAX - a) {
return false; // Would overflow
}
*result = a + b;
return true;
}
// For unsigned multiplication: check if result would wrap
// if a * b would overflow, then b > MAX / a (when a != 0)
bool safe_mul_size_t(size_t a, size_t b, size_t *result) {
if (a != 0 && b > SIZE_MAX / a) {
return false; // Would overflow
}
*result = a * b;
return true;
}
Approach 2: GCC/Clang Builtins (preferred)
bool safe_add_size_t(size_t a, size_t b, size_t *result) {
return !__builtin_add_overflow(a, b, result);
}
Key questions:
- Why is signed overflow undefined behavior in C?
- How does twoโs complement representation affect overflow detection?
- Why is
a * b / a == bnot a reliable overflow check?
Learning milestones:
- Implement unsigned overflow checks โ Addition and multiplication
- Handle signed integers โ Understand undefined behavior
- Use compiler builtins โ Learn modern approach
- Create safe_calloc wrapper โ Practical application
Project 3: Vulnerable Program Laboratory
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: N/A (must be C for realistic vulns)
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The โResume Goldโ
- Difficulty: Level 2: Intermediate
- Knowledge Area: Exploit Awareness / Vulnerability Classes
- Software or Tool: GCC with security flags disabled, GDB
- Main Book: โHacking: The Art of Exploitationโ by Jon Erickson
What youโll build: A collection of intentionally vulnerable programs demonstrating each vulnerability class (stack overflow, heap overflow, format string, integer overflow), with documentation explaining how each can be exploited.
Why it teaches exploit awareness: You canโt defend against what you donโt understand. Building vulnerable programs and understanding exactly how they fail teaches you to recognize these patterns in real code.
Core challenges youโll face:
- Disabling security features โ maps to understanding what each protects
- Creating exploitable conditions โ maps to understanding attacker requirements
- Documenting exploitation โ maps to clear threat model
- Varying difficulty levels โ maps to progressive learning
Resources for key challenges:
- โHacking: The Art of Exploitationโ Chapters 2-5
- picoCTF binary exploitation challenges - See real examples
- Protostar/Nebula exercises - Classic vulnerable VMs
Key Concepts:
- Stack Buffer Overflow: โHacking: Art of Exploitationโ Ch. 2
- Format String Exploitation: โHacking: Art of Exploitationโ Ch. 5
- Heap Exploitation Basics: โThe Shellcoderโs Handbookโ Ch. 6
Difficulty: Intermediate Time estimate: 2 weeks Prerequisites: Basic C, understanding of memory layout
Real world outcome:
vuln-lab/
โโโ stack/
โ โโโ 01_basic_overflow.c # gets() buffer overflow
โ โโโ 02_fixed_offset.c # Known offset to return address
โ โโโ 03_with_canary.c # Stack canary to bypass
โ โโโ 04_aslr_enabled.c # Need info leak
โ โโโ README.md # Exploitation walkthrough
โโโ format_string/
โ โโโ 01_info_leak.c # Read stack with %x
โ โโโ 02_arbitrary_read.c # Read any address with %s
โ โโโ 03_arbitrary_write.c # Write with %n
โ โโโ README.md
โโโ integer/
โ โโโ 01_size_overflow.c # malloc(n * size) overflow
โ โโโ 02_signed_comparison.c # Negative length bypass
โ โโโ README.md
โโโ heap/
โ โโโ 01_use_after_free.c # Dangling pointer
โ โโโ 02_double_free.c # Heap corruption
โ โโโ 03_heap_overflow.c # Overwrite chunk metadata
โ โโโ README.md
โโโ Makefile # Compile with/without protections
โโโ solutions/ # Exploit scripts (for learning)
Implementation Hints:
Each vulnerable program should:
- Have a clear, simple vulnerability
- Print helpful messages for learners
- Compile with a specific set of disabled protections
- Have an accompanying exploit script
Example Makefile:
# Disable ALL protections (educational only!)
VULN_FLAGS = -fno-stack-protector -z execstack -no-pie -Wno-format-security
# Enable ALL protections (for comparison)
SAFE_FLAGS = -fstack-protector-strong -D_FORTIFY_SOURCE=2 -pie -Wformat-security
Basic stack overflow template questions:
- How many bytes from buffer start to saved return address?
- What address should the return pointer be overwritten with?
- If NX is enabled, what technique bypasses it?
Learning milestones:
- Create basic overflow โ Understand memory layout
- Create format string vuln โ Understand printf internals
- Create integer overflow โ Understand arithmetic attacks
- Create heap corruption โ Understand allocator metadata
Project 4: Stack Canary Implementation
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C (with inline assembly)
- Alternative Programming Languages: Assembly
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The โResume Goldโ
- Difficulty: Level 3: Advanced
- Knowledge Area: Exploit Defense / Compiler Security Features
- Software or Tool: GCC, objdump, GDB
- Main Book: โComputer Systems: A Programmerโs Perspectiveโ by Bryant & OโHallaron
What youโll build: Your own stack canary protection mechanismโgenerating random canaries, inserting them in function prologues, and checking them in epilogues.
Why it teaches secure coding: Understanding how stack canaries work (and their limitations) helps you understand both the defense mechanism and how sophisticated attacks bypass them.
Core challenges youโll face:
- Generating random canaries โ maps to entropy sources, /dev/urandom
- Storing the master canary โ maps to TLS or global storage
- Inserting checks โ maps to function prologue/epilogue modification
- Terminating on failure โ maps to safe crash behavior
Resources for key challenges:
- GCC stack-protector source code - See real implementation
- โSmashing the Stack for Fun and Profitโ - Aleph One (to understand the attack)
- ProPolice paper - Original stack protector design
Key Concepts:
- Stack Frame Layout: โCSAPPโ Ch. 3.7
- Function Prologue/Epilogue: โThe Art of Assemblyโ Ch. 5
- Thread-Local Storage: โThe Linux Programming Interfaceโ Ch. 31
Difficulty: Advanced Time estimate: 2 weeks Prerequisites: Project 3, assembly language basics
Real world outcome:
$ ./canary_demo
Initializing stack canary protection...
Canary value: 0x00a83f9b7c4d2e1f (randomized)
Running protected function...
Function prologue: Canary placed on stack
Function body: Simulating buffer overflow...
Function epilogue: Checking canary...
*** STACK SMASHING DETECTED ***
Canary corrupted: expected 0x00a83f9b7c4d2e1f, got 0x4141414141414141
Aborting.
$ ./compare_with_gcc
GCC -fstack-protector-strong generates:
mov rax, QWORD PTR fs:0x28 ; Load canary from TLS
mov QWORD PTR [rbp-0x8], rax ; Store on stack
...
mov rax, QWORD PTR [rbp-0x8] ; Load from stack
xor rax, QWORD PTR fs:0x28 ; Compare with TLS
jne __stack_chk_fail ; Abort if different
Our implementation generates similar code!
Implementation Hints:
Stack canary design decisions:
-
Canary value: Should contain a NUL byte (0x00) as the first or last byte. This stops string operations (
strcpy,strcat) from copying past the canary. - Placement: Goes between local variables and saved frame pointer:
[Return Address] [Saved RBP] [CANARY] โ Attacker must overwrite this to reach return addr [Local Variables] [Buffer] โ Overflow starts here - Per-thread storage: Use thread-local storage (TLS) so each thread has its own reference canary. On x86-64 Linux, GCC uses
fs:0x28.
Implementation approach:
- At program start: Generate random canary using
/dev/urandom - Store in TLS or global (simpler for learning)
- In each protected function:
- Prologue: Copy canary to stack
- Epilogue: Compare stack canary with stored value
- If mismatch: Call abort() with message
Questions to consider:
- Why include a NUL byte in the canary?
- How can attackers bypass canaries? (Info leak)
- Whatโs the difference between
-fstack-protectorand-fstack-protector-strong?
Learning milestones:
- Generate random canary โ Use /dev/urandom
- Insert canary in function โ Modify prologue/epilogue
- Detect overflow โ Compare and abort
- Compare with GCC โ Analyze real implementation
Project 5: Format String Vulnerability Demonstrator
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: Python (for exploits)
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The โResume Goldโ
- Difficulty: Level 3: Advanced
- Knowledge Area: Exploit Awareness / Format Strings
- Software or Tool: GDB, pwntools, printf source
- Main Book: โHacking: The Art of Exploitationโ by Jon Erickson
What youโll build: A comprehensive demonstration of format string attacksโreading stack values, reading arbitrary memory, writing to arbitrary memory, and achieving code execution.
Why it teaches exploit awareness: Format string bugs are underestimated but devastating. Understanding exactly how %n writes memory is crucial for both offense and defense.
Core challenges youโll face:
- Understanding printf internals โ maps to variadic functions, va_list
- Leaking stack values โ maps to %x and %p usage
- Arbitrary read with %s โ maps to controlling address on stack
- Arbitrary write with %n โ maps to byte-by-byte writing
Resources for key challenges:
- โHacking: Art of Exploitationโ Chapter 5 - Format Strings
- Exploiting Format String Vulnerabilities (USENIX paper)
- scut/team teso formatstring paper
Key Concepts:
- Variadic Functions in C: โC Programming: A Modern Approachโ Ch. 26
- Format String Exploitation: โHacking: Art of Exploitationโ Ch. 5
- RELRO and GOT Protection: Hardening ELF binaries article
Difficulty: Advanced Time estimate: 2 weeks Prerequisites: Project 3, understanding of stack layout
Real world outcome:
$ ./format_demo
Format String Vulnerability Demonstrator
-----------------------------------------
[Level 1: Stack Leak]
Enter format string: %x.%x.%x.%x.%x
Output: deadbeef.cafebabe.12345678.ffff0000.41414141
โ Leaked 5 values from stack!
[Level 2: Arbitrary Read]
Target address: 0x404040 (contains "SECRET_KEY")
Enter format string: [crafted payload with address]
Output: SECRET_KEY
โ Read arbitrary memory!
[Level 3: Arbitrary Write]
Target variable at 0x404060 = 0
Enter format string: [crafted payload with %n]
Target variable now = 1337
โ Wrote arbitrary value!
[Level 4: Code Execution]
GOT entry for exit() at 0x404018
win() function at 0x401337
Enter format string: [GOT overwrite payload]
โ Calling exit()... but it's been hijacked!
You win! Format string exploitation complete.
Implementation Hints:
Understanding the attack:
-
Why it works:
printf(user_input)treats user input AS the format string. If user provides%x, printf reads from stack looking for corresponding argument. - Reading with %x:
printf("%x"); // Reads 4 bytes from where arg would be printf("%lx"); // Reads 8 bytes printf("%7$x"); // Direct parameter access - 7th "argument" - Reading arbitrary memory with %s:
If you can control an address on the stack (often through the format string itself),
%swill read from that address:Input: AAAA%7$s Stack: [AAAA][...][...][...][...][...][fmt string ptr] %7$s reads string from address 0x41414141 - Writing with %n:
%nwrites the count of characters printed so far to an address on the stack.int count; printf("AAAA%n", &count); // count = 4Combined with direct parameter access, attacker controls the address.
Questions to explore:
- What happens if you write to a read-only address?
- How does FORTIFY_SOURCE protect against format strings?
- Why is
%noften disabled in production systems?
Learning milestones:
- Leak stack values โ Understand printf argument handling
- Read arbitrary memory โ Master %s exploitation
- Write single byte โ Use %hhn for precision
- Overwrite GOT โ Achieve code execution
Project 6: Safe Memory Allocator Wrapper
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 3. The โService & Supportโ Model
- Difficulty: Level 2: Intermediate
- Knowledge Area: Secure Coding / Memory Safety
- Software or Tool: Valgrind, AddressSanitizer
- Main Book: โEffective C, 2nd Editionโ by Robert C. Seacord
What youโll build: A secure memory allocation wrapper that prevents integer overflow in size calculations, zeroes memory on free (preventing info leaks), detects double-frees, and tracks allocations for debugging.
Why it teaches secure coding: Most heap vulnerabilities stem from allocation mistakes. Building your own secure allocator teaches you what can go wrong and how to prevent it.
Core challenges youโll face:
- Safe size calculation โ maps to integer overflow before malloc
- Preventing use-after-free โ maps to poison freed memory
- Detecting double-free โ maps to allocation tracking
- Memory zeroing on free โ maps to preventing info leaks
Resources for key challenges:
- โEffective C, 2nd Editionโ Chapter 7 - Dynamic Memory
- CERT C: MEM00-C through MEM11-C
- OpenBSD malloc implementation - secure_malloc
Key Concepts:
- calloc vs malloc: CERT C MEM04-C
- Clearing Sensitive Data: CERT C MEM03-C
- Allocation Tracking: Valgrind internals
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Project 2 (integer overflow), basic dynamic memory
Real world outcome:
$ ./test_safe_alloc
Testing safe_malloc...
โ Normal allocation: 1024 bytes allocated
โ Zero size: Returns NULL
โ Overflow protection: safe_calloc(SIZE_MAX, 2) returns NULL
Testing safe_free...
โ Memory zeroed on free (sensitive data cleared)
โ Double-free detected: FATAL: double free at 0x12340000
โ Use-after-free detected: Memory poisoned with 0xDEADBEEF
Testing safe_realloc...
โ Normal realloc: 1024 -> 2048 bytes
โ Shrink realloc: Zeroes extra bytes
โ Overflow protection: safe_realloc(ptr, SIZE_MAX) returns NULL
Memory stats:
Allocations: 15
Frees: 14
Current allocated: 1024 bytes
LEAK DETECTED: 1 allocation not freed!
Implementation Hints:
Key features to implement:
- Safe size calculation (use Project 2):
void *safe_calloc(size_t count, size_t size) { size_t total; if (!safe_mul_size_t(count, size, &total)) { errno = ENOMEM; return NULL; // Overflow detected } void *ptr = calloc(1, total); // Track allocation... return ptr; } - Allocation tracking (for double-free detection):
typedef struct allocation { void *ptr; size_t size; bool freed; struct allocation *next; } allocation_t; - Memory poisoning (detect use-after-free):
void safe_free(void *ptr) { if (ptr == NULL) return; allocation_t *alloc = find_allocation(ptr); if (alloc->freed) { abort_with_message("Double free detected!"); } memset(ptr, 0xDE, alloc->size); // Poison with recognizable pattern alloc->freed = true; free(ptr); }
Questions to consider:
- Why zero memory on free? (Heartbleed-style leaks)
- How does AddressSanitizer implement similar checks?
- Whatโs the performance overhead of tracking?
Learning milestones:
- Implement overflow protection โ Safe calloc
- Track allocations โ Build allocation list
- Detect double-free โ Check freed flag
- Zero on free โ Prevent info leaks
Project 7: Bounds-Checking Array Library
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: C++ (has std::vector), Rust (has slice bounds)
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 2. The โMicro-SaaS / Pro Toolโ
- Difficulty: Level 2: Intermediate
- Knowledge Area: Secure Coding / Memory Safety
- Software or Tool: AddressSanitizer, Valgrind
- Main Book: โC Interfaces and Implementationsโ by David R. Hanson
What youโll build: A bounds-checked dynamic array type for C that prevents buffer overflows, includes length tracking, and provides safe accessor functions.
Why it teaches secure coding: C arrays donโt know their own lengthโthis is the root cause of most buffer overflows. Building a โfat pointerโ array teaches you what safe languages do automatically.
Core challenges youโll face:
- Storing length with data โ maps to struct design, โfat pointersโ
- Bounds checking overhead โ maps to performance vs safety tradeoffs
- API design โ maps to making safe defaults easy
- Memory management โ maps to preventing leaks, ownership
Resources for key challenges:
- โC Interfaces and Implementationsโ Chapter 14 - Sequence
- โ21st Century Cโ Chapter 6 - Data structures
- Rust slice implementation - Inspiration for design
Key Concepts:
- Fat Pointers: โThe Rust Programming Languageโ Ch. 4
- Defensive Programming: โCode Completeโ Ch. 8
- API Design: โC Interfaces and Implementationsโ Introduction
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Project 1 (safe strings), dynamic memory
Real world outcome:
$ ./test_safe_array
Creating array...
โ array_new(10, sizeof(int)) created with capacity 10
Testing bounds checking...
โ array_get(arr, 5) returns element at index 5
โ array_get(arr, 15) returns NULL (out of bounds!)
โ array_set(arr, 100, &val) returns false (out of bounds!)
Testing dynamic growth...
โ array_push grows array automatically
โ Capacity doubled: 10 -> 20 -> 40
Testing iteration...
โ array_foreach provides safe iteration
Testing security...
โ Cannot access beyond length, even within capacity
โ Integer overflow in size calculation prevented
Memory test with Valgrind:
No memory leaks detected
No invalid reads/writes
Implementation Hints:
Structure design:
typedef struct {
void *data; // The actual array data
size_t length; // Current number of elements
size_t capacity; // Allocated space
size_t element_size; // Size of each element
} safe_array_t;
Key operations:
// Create array with initial capacity
safe_array_t *array_new(size_t capacity, size_t element_size);
// Get element with bounds check
void *array_get(safe_array_t *arr, size_t index);
// Set element with bounds check
bool array_set(safe_array_t *arr, size_t index, const void *value);
// Push element, growing if needed
bool array_push(safe_array_t *arr, const void *value);
// Safe iteration
#define array_foreach(arr, type, var) \
for (size_t _i = 0; _i < (arr)->length && \
((var) = *(type*)array_get(arr, _i), 1); _i++)
Questions to explore:
- How does this compare to
std::vectorin C++? - Whatโs the performance cost of bounds checking?
- How would you make this thread-safe?
Learning milestones:
- Implement basic structure โ Length-aware arrays
- Add bounds checking โ Safe accessors
- Implement growth โ Dynamic resizing
- Create iteration โ Safe enumeration
Project 8: Heap Overflow Detector
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: Python (for analysis)
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 3. The โService & Supportโ Model
- Difficulty: Level 3: Advanced
- Knowledge Area: Exploit Defense / Heap Security
- Software or Tool: glibc malloc, GDB, custom allocator
- Main Book: โThe Shellcoderโs Handbookโ
What youโll build: A custom allocator wrapper that adds โred zonesโ (guard bytes) around allocations to detect heap buffer overflows at runtime.
Why it teaches exploit awareness: Heap overflows corrupt allocator metadata, leading to arbitrary writes. Adding canaries around heap chunks teaches you how tools like AddressSanitizer work.
Core challenges youโll face:
- Adding metadata to allocations โ maps to header/footer design
- Checking red zones โ maps to when to verify
- Handling realloc โ maps to preserving guards during resize
- Performance impact โ maps to memory overhead
Resources for key challenges:
- AddressSanitizer paper - How the pros do it
- Electric Fence documentation - Classic debugging malloc
- โUnderstanding the Linux Kernelโ - glibc malloc internals
Key Concepts:
- Heap Chunk Layout: โThe Shellcoderโs Handbookโ Ch. 6
- Memory Debugging: Electric Fence, DUMA documentation
- Guard Pages/Bytes: AddressSanitizer design
Difficulty: Advanced Time estimate: 2 weeks Prerequisites: Project 6 (safe allocator), heap internals
Real world outcome:
$ ./test_heap_overflow
Testing red zone detection...
Allocating 64 bytes with guard zones...
Memory layout:
[REDZONE 16 bytes][USER DATA 64 bytes][REDZONE 16 bytes]
0xDEADBEEF x 4 | your data here | 0xDEADBEEF x 4
Writing one byte past buffer...
Calling checked_free()...
*** HEAP OVERFLOW DETECTED ***
Corruption in trailing red zone at offset 0
Expected: 0xDEADBEEF, Found: 0xDEADBE41
Allocation backtrace:
#0 checked_malloc() at heap_guard.c:42
#1 main() at test.c:15
Testing underflow...
Writing before buffer...
*** HEAP UNDERFLOW DETECTED ***
Corruption in leading red zone at offset 12
Implementation Hints:
Memory layout with guards:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Allocation Header โ
โ - Original size โ
โ - Magic number โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ LEADING RED ZONE โ
ptr - REDZONE_SIZE โ Filled with GUARD_PATTERN โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
ptr (returned) โโโโบโ USER DATA โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ TRAILING RED ZONE โ
โ Filled with GUARD_PATTERN โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Implementation approach:
#define REDZONE_SIZE 16
#define GUARD_PATTERN 0xDEADBEEF
void *checked_malloc(size_t size) {
// Allocate: header + leading_redzone + user_data + trailing_redzone
size_t total = sizeof(header_t) + REDZONE_SIZE + size + REDZONE_SIZE;
void *raw = malloc(total);
// Fill header with metadata
header_t *header = (header_t *)raw;
header->size = size;
header->magic = MAGIC_NUMBER;
// Fill red zones with guard pattern
fill_guard(raw + sizeof(header_t), REDZONE_SIZE);
fill_guard(raw + sizeof(header_t) + REDZONE_SIZE + size, REDZONE_SIZE);
// Return pointer to user data
return raw + sizeof(header_t) + REDZONE_SIZE;
}
void checked_free(void *ptr) {
// Calculate back to header
header_t *header = ptr - REDZONE_SIZE - sizeof(header_t);
// Verify red zones
if (!check_guard(ptr - REDZONE_SIZE, REDZONE_SIZE)) {
report_underflow(header);
}
if (!check_guard(ptr + header->size, REDZONE_SIZE)) {
report_overflow(header);
}
free(header);
}
Learning milestones:
- Design memory layout โ Header + guards + data
- Implement allocation wrapper โ Add guard bytes
- Implement free wrapper โ Check guards
- Add diagnostics โ Detailed error reporting
Project 9: Input Validation Framework
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: Python, Go
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 3. The โService & Supportโ Model
- Difficulty: Level 2: Intermediate
- Knowledge Area: Secure Coding / Input Handling
- Software or Tool: Regular expressions, fuzzing
- Main Book: โEffective C, 2nd Editionโ by Robert C. Seacord
What youโll build: A comprehensive input validation library with validators for integers, strings, paths, emails, and custom patternsโreturning safe, validated values or clear error codes.
Why it teaches secure coding: Invalid input is the root cause of most vulnerabilities. Building a validation framework teaches you to think about all the ways input can be malicious.
Core challenges youโll face:
- Integer range validation โ maps to MIN/MAX checks, overflow
- String sanitization โ maps to length limits, character whitelist
- Path traversal prevention โ maps to rejecting ../, symlinks
- Canonical forms โ maps to normalization before validation
Resources for key challenges:
- OWASP Input Validation Cheat Sheet
- CERT C: STR00-C through STR38-C (string validation)
- CWE-20: Improper Input Validation
Key Concepts:
- Whitelisting vs Blacklisting: OWASP guidelines
- Canonicalization: CERT C FIO02-C
- Defense in Depth: Multiple validation layers
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Project 1 (safe strings), regex basics
Real world outcome:
$ ./test_input_validator
Testing integer validation...
โ validate_int("123", 0, 1000) = 123
โ validate_int("-5", 0, 1000) = ERROR_RANGE
โ validate_int("99999999999999", ...) = ERROR_OVERFLOW
โ validate_int("12abc", ...) = ERROR_FORMAT
Testing string validation...
โ validate_string("hello", 1, 10, ALPHA) = "hello"
โ validate_string("hello123", ..., ALPHA) = ERROR_INVALID_CHARS
โ validate_string("", 1, 10, ...) = ERROR_TOO_SHORT
โ validate_string(NULL, ...) = ERROR_NULL
Testing path validation...
โ validate_path("/home/user/file.txt") = validated path
โ validate_path("../../../etc/passwd") = ERROR_TRAVERSAL
โ validate_path("/etc/passwd") = ERROR_OUTSIDE_ROOT
โ validate_path("file\x00.txt") = ERROR_NULL_BYTE
Testing email validation...
โ validate_email("user@example.com") = valid
โ validate_email("user@") = ERROR_FORMAT
โ validate_email("user+tag@sub.example.com") = valid
All 24 tests passed!
Implementation Hints:
Validation design principles:
- Fail secure: Invalid input should fail, not be silently accepted
- Whitelist over blacklist: Accept known-good, not reject known-bad
- Canonicalize first: Convert to standard form before validating
- Check all properties: Length, characters, format, range
Example validators:
typedef enum {
VALIDATE_OK = 0,
VALIDATE_ERROR_NULL,
VALIDATE_ERROR_LENGTH,
VALIDATE_ERROR_CHARS,
VALIDATE_ERROR_RANGE,
VALIDATE_ERROR_FORMAT,
VALIDATE_ERROR_TRAVERSAL
} validate_result_t;
// Integer validation
validate_result_t validate_int(
const char *str,
long min,
long max,
long *result
);
// String validation
typedef enum {
CHARSET_ALPHA,
CHARSET_ALNUM,
CHARSET_ASCII_PRINTABLE,
CHARSET_CUSTOM
} charset_t;
validate_result_t validate_string(
const char *str,
size_t min_len,
size_t max_len,
charset_t allowed,
char *output,
size_t output_size
);
// Path validation
validate_result_t validate_path(
const char *path,
const char *allowed_root,
char *canonical_path,
size_t path_size
);
Questions to consider:
- Whatโs the difference between
realpath()and manual validation? - How do you handle Unicode/UTF-8 in C?
- What about timing attacks in string comparison?
Learning milestones:
- Implement integer validator โ Range, format, overflow checks
- Implement string validator โ Length, charset, sanitization
- Implement path validator โ Prevent traversal attacks
- Build test suite โ Comprehensive edge cases
Project 10: Return-to-libc Attack Lab
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C (targets), Python (exploits)
- Alternative Programming Languages: Assembly
- Coolness Level: Level 5: Pure Magic (Super Cool)
- Business Potential: 1. The โResume Goldโ
- Difficulty: Level 3: Advanced
- Knowledge Area: Exploit Awareness / NX Bypass
- Software or Tool: GDB, pwntools, checksec
- Main Book: โHacking: The Art of Exploitationโ by Jon Erickson
What youโll build: A series of progressively difficult return-to-libc exploits that bypass NX/DEP protection by reusing existing library code instead of injecting shellcode.
Why it teaches exploit awareness: When NX prevents code execution on the stack, attackers call existing functions like system(). Understanding this teaches you why code-reuse attacks exist and what defenses remain.
Core challenges youโll face:
- Finding libc addresses โ maps to ASLR considerations
- Setting up function arguments โ maps to calling conventions
- Chaining multiple calls โ maps to return chaining
- Finding โ/bin/shโ string โ maps to string gadgets in libc
Resources for key challenges:
- โHacking: Art of Exploitationโ Chapter 5
- ROP Emporium - ret2win challenge
- LiveOverflow YouTube - ret2libc walkthrough
Key Concepts:
- Calling Conventions: System V ABI for x64
- GOT/PLT: โPractical Binary Analysisโ Ch. 2
- ASLR: Address Space Layout Randomization
Difficulty: Advanced Time estimate: 2-3 weeks Prerequisites: Projects 3-5, buffer overflow basics
Real world outcome:
$ cd ret2libc-lab
$ ./level1
Simple ret2libc: NX enabled, no ASLR, no canary
Enter name: [overflow payload with system() address]
$ whoami
pwned
$ ./level2
ret2libc with argument: Must pass correct argument to system()
[payload with gadget: pop rdi; ret + "/bin/sh" addr + system()]
$ id
uid=1000(user) gid=1000(user) groups=1000(user)
$ ./level3
ret2libc with ASLR: Must leak libc address first
[leak puts@got, calculate libc base, call system("/bin/sh")]
$ cat /flag
FLAG{ret2libc_master}
$ ./level4
Full chain: leak + ROP + shell
[complete exploit with info leak and chained calls]
Implementation Hints:
ret2libc concept:
Normal return: ret2libc:
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Return Addr โ โ caller โ system() โ โ libc function
โโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโค
โ Saved RBP โ โ pop rdi;ret โ โ gadget
โโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโค
โ โ โ "/bin/sh" โ โ argument
โ Buffer โ โ addr โ
โ โ โโโโโโโโโโโโโโโค
โ โ โ AAAA... โ โ overflow
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
For x64, arguments are in registers (RDI, RSI, RDXโฆ), so you need โgadgetsโ:
- Find
pop rdi; retgadget in binary or libc - Stack: [gadget addr][โ/bin/shโ addr][system addr]
- Gadget pops โ/bin/shโ into RDI, returns to system()
Finding gadgets:
$ ROPgadget --binary ./vuln | grep "pop rdi"
0x0000000000401234 : pop rdi ; ret
$ strings -t x /lib/x86_64-linux-gnu/libc.so.6 | grep "/bin/sh"
18ce57 /bin/sh
Questions to explore:
- Why canโt you just call
system()directly (without gadget)? - How does ASLR affect ret2libc attacks?
- Whatโs the difference between ret2libc and ROP?
Learning milestones:
- Basic ret2libc โ Call system() with static address
- With gadgets โ Set up argument in register
- With ASLR โ Leak address first
- Chain calls โ Multiple function calls
Project 11: Static Analysis Tool (Basic)
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: Python
- Alternative Programming Languages: C, Go
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 4. The โOpen Coreโ Infrastructure
- Difficulty: Level 3: Advanced
- Knowledge Area: Security Tools / Code Analysis
- Software or Tool: pycparser, Clang AST
- Main Book: โSecure Coding in C and C++โ by Robert C. Seacord
What youโll build: A static analysis tool that scans C source code for common vulnerability patternsโdangerous functions, format string bugs, potential integer overflows, and missing bounds checks.
Why it teaches secure coding: Building an analyzer forces you to formally define what โdangerousโ code looks like and creates a tool you can use on real projects.
Core challenges youโll face:
- Parsing C code โ maps to using pycparser or Clang
- Pattern matching โ maps to AST traversal
- Reducing false positives โ maps to context-aware analysis
- Reporting findings โ maps to useful output format
Resources for key challenges:
- pycparser documentation
- Clang Static Analyzer documentation
- Semgrep rule writing guide
Key Concepts:
- Abstract Syntax Trees: Compiler textbooks
- Taint Analysis: โSecure Programming with Static Analysisโ Ch. 4
- Pattern-Based Detection: Semgrep approach
Difficulty: Advanced Time estimate: 3-4 weeks Prerequisites: All previous projects, parsing basics
Real world outcome:
$ ./cscan vulnerable.c
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
C Security Scanner Report
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
File: vulnerable.c
[HIGH] Dangerous Function: gets()
Line 15: gets(buffer);
Issue: gets() has no bounds checking. Use fgets() instead.
CWE: CWE-120 (Buffer Copy without Checking Size)
[HIGH] Format String Vulnerability
Line 23: printf(user_input);
Issue: User-controlled format string. Use printf("%s", ...).
CWE: CWE-134 (Use of Externally-Controlled Format String)
[MEDIUM] Potential Integer Overflow
Line 31: size_t total = count * element_size;
Issue: Multiplication may overflow. Use safe_mul().
CWE: CWE-190 (Integer Overflow)
[MEDIUM] Unbounded String Copy
Line 45: strcpy(dest, source);
Issue: strcpy() has no bounds check. Use strncpy() or strlcpy().
CWE: CWE-120
[LOW] Unchecked Return Value
Line 52: malloc(size);
Issue: malloc() return value not checked for NULL.
CWE: CWE-252 (Unchecked Return Value)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary: 2 HIGH, 2 MEDIUM, 1 LOW findings
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Implementation Hints:
Two approaches:
Approach 1: Regex-based (simpler, more false positives)
import re
dangerous_functions = [
(r'\bgets\s*\(', 'gets() has no bounds check', 'HIGH'),
(r'\bstrcpy\s*\(', 'strcpy() has no bounds check', 'MEDIUM'),
(r'\bprintf\s*\(\s*[a-zA-Z_]\w*\s*\)', 'Possible format string', 'HIGH'),
(r'\bscanf\s*\(\s*"%s"', 'scanf %s has no bounds', 'HIGH'),
]
Approach 2: AST-based (more accurate)
import pycparser
class VulnChecker(pycparser.c_ast.NodeVisitor):
def visit_FuncCall(self, node):
func_name = node.name.name if hasattr(node.name, 'name') else None
if func_name == 'gets':
self.report('HIGH', 'Dangerous function: gets()', node.coord)
elif func_name == 'printf':
if len(node.args.exprs) == 1:
arg = node.args.exprs[0]
if isinstance(arg, pycparser.c_ast.ID):
self.report('HIGH', 'Format string vulnerability', node.coord)
self.generic_visit(node)
Detection rules to implement:
- Dangerous functions (gets, strcpy, sprintf, etc.)
- Format string bugs (printf with variable format)
- Integer overflow (multiplication before allocation)
- Unchecked return values (malloc, fopen)
- Buffer size mismatches
Learning milestones:
- Parse C code โ Use pycparser or Clang
- Detect dangerous functions โ Pattern matching
- Detect format strings โ Argument analysis
- Report findings โ Useful output format
Project 12: Use-After-Free Demonstrator
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: Python (for exploit)
- Coolness Level: Level 5: Pure Magic (Super Cool)
- Business Potential: 1. The โResume Goldโ
- Difficulty: Level 4: Expert
- Knowledge Area: Exploit Awareness / Heap Exploitation
- Software or Tool: GDB, heap visualization tools
- Main Book: โThe Shellcoderโs Handbookโ
What youโll build: A demonstration of use-after-free vulnerabilities and exploitationโshowing how freed memory can be reallocated and abused to achieve code execution.
Why it teaches exploit awareness: UAF is one of the most common vulnerability classes in browsers and operating systems. Understanding it is essential for modern security work.
Core challenges youโll face:
- Understanding heap reuse โ maps to how freed chunks are recycled
- Controlling freed data โ maps to timing and allocation order
- Hijacking control flow โ maps to overwriting function pointers
- Heap grooming โ maps to manipulating heap state
Resources for key challenges:
- โThe Shellcoderโs Handbookโ Chapter 6
- Azeria Labs - Heap Exploitation
- how2heap repository (Shellphish)
Key Concepts:
- Heap Chunk Lifecycle: glibc malloc internals
- Fastbin/Tcache: Modern allocator optimizations
- Type Confusion: Reusing memory as different type
Difficulty: Expert Time estimate: 3-4 weeks Prerequisites: Projects 3, 6, 8, heap internals
Real world outcome:
$ ./uaf_demo
=== Use-After-Free Demonstration ===
Step 1: Allocate object with function pointer
Object at 0x55a0001234a0
object->callback = 0x55a000001234 (good_function)
Step 2: Free the object
Freed object (but pointer still exists!)
Dangling pointer: 0x55a0001234a0
Step 3: Allocate new data of same size
New allocation at: 0x55a0001234a0 (same address!)
Writing "AAAA" + evil_function address...
Step 4: Call the dangling pointer's callback
Calling object->callback()...
*** HIJACKED ***
evil_function() called!
This would be shellcode in a real exploit.
=== Exploitation Successful ===
Understanding what happened:
1. Original object freed, but pointer kept
2. New allocation reused same memory
3. Attacker data overwrote function pointer
4. Calling original pointer's method = calling attacker's code
Implementation Hints:
UAF exploitation concept:
typedef struct {
char name[32];
void (*callback)(void); // Function pointer
} user_t;
user_t *user = malloc(sizeof(user_t));
user->callback = good_function;
free(user); // Freed, but pointer still valid
// Attacker causes new allocation of same size
char *evil = malloc(sizeof(user_t));
memcpy(evil + 32, &evil_addr, 8); // Overwrite callback
// Victim uses dangling pointer
user->callback(); // Calls evil_addr!
Heap allocation strategy:
- glibc reuses recently freed chunks (fastbin LIFO)
- Same-size allocation likely gets same address
- Attacker controls content of new allocation
- Original pointer dereferences attacker data
Questions to explore:
- What triggers the same-address reuse?
- How do tcache and fastbins affect UAF?
- How does AddressSanitizer detect UAF?
- What defenses exist (MTE, heap randomization)?
Learning milestones:
- Demonstrate dangling pointer โ Show the bug
- Achieve memory reuse โ Same address allocation
- Overwrite function pointer โ Hijack control
- Achieve code execution โ Complete exploit
Project 13: FORTIFY_SOURCE Implementation
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: N/A
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The โResume Goldโ
- Difficulty: Level 4: Expert
- Knowledge Area: Secure Coding / Compiler Defenses
- Software or Tool: GCC, glibc headers
- Main Book: โEffective C, 2nd Editionโ by Robert C. Seacord
What youโll build: Your own implementation of FORTIFY_SOURCE-style compile-time and runtime bounds checking for string functions.
Why it teaches secure coding: FORTIFY_SOURCE is glibcโs defense layer that prevents many buffer overflows. Understanding how it works teaches you both the technique and its limitations.
Core challenges youโll face:
- Compile-time size detection โ maps to __builtin_object_size
- Function wrappers โ maps to replacing libc functions
- Runtime checks โ maps to abort on overflow
- Performance balance โ maps to when to check
Resources for key challenges:
- glibc FORTIFY_SOURCE source code
- GCC __builtin_object_size documentation
- Red Hat FORTIFY_SOURCE blog post
Key Concepts:
- Object Size Builtin: GCC documentation
- Macro Replacement: glibc bits/string_fortified.h
- Compile-Time vs Runtime: FORTIFY_SOURCE levels
Difficulty: Expert Time estimate: 2-3 weeks Prerequisites: Projects 1, 7, macro programming
Real world outcome:
$ cat test.c
char buf[10];
strcpy(buf, argv[1]); // Potentially dangerous!
$ gcc -D_FORTIFY_SOURCE=2 test.c -o test
(Our fortified headers intercept strcpy)
$ ./test "short"
OK
$ ./test "this is a very long string"
*** buffer overflow detected ***: terminated
Aborted
$ gcc -DFORTIFY_EXPLAIN -D_FORTIFY_SOURCE=2 test.c -o test
$ ./test "this is a very long string"
FORTIFY: strcpy overflow detected
Destination size: 10 bytes (known at compile time)
Source size: 28 bytes
Call site: test.c:3
*** buffer overflow detected ***: terminated
Implementation Hints:
How FORTIFY_SOURCE works:
- Compile-time size detection:
char buf[10]; __builtin_object_size(buf, 0); // Returns 10 char *ptr = malloc(20); __builtin_object_size(ptr, 0); // Returns 20 (if optimizer knows) - Function replacement via macros:
// In fortified header: #define strcpy(dest, src) \ __fortified_strcpy(dest, src, __builtin_object_size(dest, 0)) static inline char *__fortified_strcpy(char *dest, const char *src, size_t dest_size) { size_t src_len = strlen(src) + 1; if (src_len > dest_size) { __fortify_fail("buffer overflow"); } return __builtin_strcpy(dest, src); } - Different FORTIFY levels:
- Level 1: Check when size is known at compile time
- Level 2: Also check with stricter object size tracking
Questions to consider:
- When does
__builtin_object_sizereturn -1 (unknown)? - Why canโt FORTIFY_SOURCE catch all overflows?
- Whatโs the performance overhead?
Learning milestones:
- Understand __builtin_object_size โ Compile-time size
- Create wrapper functions โ Intercept libc calls
- Implement runtime checks โ Abort on overflow
- Compare with glibc โ Study real implementation
Project 14: Secure Configuration Parser
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: Python, Rust
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 2. The โMicro-SaaS / Pro Toolโ
- Difficulty: Level 2: Intermediate
- Knowledge Area: Secure Coding / Input Parsing
- Software or Tool: Fuzzer (AFL++), Valgrind
- Main Book: โC Interfaces and Implementationsโ by David R. Hanson
What youโll build: A secure configuration file parser that handles INI/TOML-like syntax with proper bounds checking, integer validation, and path safetyโdemonstrating secure parsing techniques.
Why it teaches secure coding: Parsers are a common source of vulnerabilities. Building a secure parser teaches you to handle malformed input, prevent injection, and validate all data.
Core challenges youโll face:
- Handling malformed input โ maps to graceful error handling
- Line length limits โ maps to bounded buffers
- String escaping โ maps to preventing injection
- Type conversion safety โ maps to integer overflow in values
Resources for key challenges:
- โC Interfaces and Implementationsโ - Parsing chapter
- AFL++ fuzzing tutorial - Find your parser bugs
- OWASP - Configuration file injection
Key Concepts:
- Parser State Machine: Compiler textbooks
- Defensive Parsing: โSecure Coding in Cโ Ch. 8
- Fuzz Testing: AFL++ documentation
Difficulty: Intermediate Time estimate: 2 weeks Prerequisites: Projects 1, 2, 9
Real world outcome:
$ cat config.ini
[database]
host = localhost
port = 5432
max_connections = 100
[paths]
log_file = /var/log/app.log
data_dir = ../../../etc/passwd # Attack attempt!
[security]
timeout = 999999999999999999 # Overflow attempt!
$ ./secure_parser config.ini
Parsing config.ini...
[database]
host = "localhost" (string, 9 chars)
port = 5432 (integer, range: 1-65535 โ)
max_connections = 100 (integer, range: 1-10000 โ)
[paths]
log_file = "/var/log/app.log" (path, validated โ)
data_dir = ERROR: Path traversal detected ("../../../etc/passwd")
[security]
timeout = ERROR: Integer overflow (value exceeds INT_MAX)
Parse complete: 4 values loaded, 2 errors
Implementation Hints:
Secure parsing principles:
- Bounded reads:
char line[MAX_LINE_LENGTH + 1]; if (fgets(line, sizeof(line), file) == NULL) break; // Check if line was truncated size_t len = strlen(line); if (len == MAX_LINE_LENGTH && line[len-1] != '\n') { // Line too long - error or skip to newline } - Type-safe value parsing:
typedef enum { CONFIG_STRING, CONFIG_INTEGER, CONFIG_PATH, CONFIG_BOOLEAN } config_type_t; typedef struct { const char *key; config_type_t type; long min_value; // For integers long max_value; size_t max_length; // For strings const char *base_path; // For path validation } config_schema_t; - Schema-based validation:
config_schema_t schema[] = { {"port", CONFIG_INTEGER, 1, 65535, 0, NULL}, {"host", CONFIG_STRING, 0, 0, 255, NULL}, {"log_file", CONFIG_PATH, 0, 0, PATH_MAX, "/var/log"}, {NULL} };
Questions to consider:
- How do you handle UTF-8 in config files?
- What about comments and whitespace?
- How do you prevent shell injection in path values?
Learning milestones:
- Parse basic INI format โ Section and key=value
- Add type validation โ Integer bounds, string length
- Add path validation โ Prevent traversal
- Fuzz the parser โ Find edge cases
Project 15: Complete Secure Coding Toolkit
- File: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
- Main Programming Language: C
- Alternative Programming Languages: Companion tools in Python
- Coolness Level: Level 5: Pure Magic (Super Cool)
- Business Potential: 4. The โOpen Coreโ Infrastructure
- Difficulty: Level 4: Expert
- Knowledge Area: Complete Security Library
- Software or Tool: All previous projects
- Main Book: All previous books
What youโll build: A unified secure coding library combining all previous projectsโsafe strings, safe integers, safe memory, input validation, and security utilitiesโwith comprehensive documentation.
Why it teaches secure coding: Integration forces you to think about API consistency, documentation, and real-world usability of security code.
Core challenges youโll face:
- API consistency โ maps to naming, error handling uniformity
- Documentation โ maps to making it usable by others
- Testing โ maps to comprehensive test coverage
- Performance โ maps to overhead measurement
Time estimate: 4-6 weeks Prerequisites: All previous projects
Real world outcome:
libsecurec/
โโโ include/
โ โโโ securec.h # Master header
โ โโโ securec/string.h # Safe string functions
โ โโโ securec/memory.h # Safe allocation
โ โโโ securec/integer.h # Safe arithmetic
โ โโโ securec/validate.h # Input validation
โ โโโ securec/crypto.h # Secure memory clearing
โโโ src/
โ โโโ string.c
โ โโโ memory.c
โ โโโ integer.c
โ โโโ validate.c
โ โโโ crypto.c
โโโ tests/
โ โโโ test_string.c
โ โโโ test_memory.c
โ โโโ ...
โโโ docs/
โ โโโ API.md
โ โโโ SECURITY.md
โ โโโ EXAMPLES.md
โโโ examples/
โ โโโ secure_server.c
โ โโโ config_parser.c
โโโ Makefile
โโโ README.md
Usage example:
#include <securec.h>
int main(int argc, char **argv) {
// Safe string handling
char buffer[64];
if (sc_strlcpy(buffer, argv[1], sizeof(buffer)) >= sizeof(buffer)) {
fprintf(stderr, "Input truncated\n");
return 1;
}
// Safe integer parsing
long port;
if (sc_strtol_safe(argv[2], 1, 65535, &port) != SC_OK) {
fprintf(stderr, "Invalid port\n");
return 1;
}
// Safe memory allocation
size_t count = 1000, size = 400;
void *data = sc_calloc_safe(count, size); // Overflow-checked
if (!data) {
fprintf(stderr, "Allocation failed\n");
return 1;
}
// Secure memory clearing
sc_memzero(password, sizeof(password)); // Can't be optimized away
sc_free(data);
return 0;
}
Implementation Hints:
API design principles:
- Consistent naming:
sc_prefix for all functions - Consistent error handling: Return codes or NULL
- Compile-time checks where possible: Static assertions
- Runtime checks for dynamic values: Bounds, overflow
Library structure:
// securec.h - Master header
#ifndef SECUREC_H
#define SECUREC_H
#include <securec/config.h> // Library configuration
#include <securec/types.h> // Common types and error codes
#include <securec/string.h> // Safe string functions
#include <securec/memory.h> // Safe allocation
#include <securec/integer.h> // Safe arithmetic
#include <securec/validate.h> // Input validation
// Error codes
typedef enum {
SC_OK = 0,
SC_ERROR_NULL,
SC_ERROR_OVERFLOW,
SC_ERROR_BOUNDS,
SC_ERROR_FORMAT,
SC_ERROR_MEMORY
} sc_result_t;
#endif
Learning milestones:
- Integrate all components โ Unified API
- Write documentation โ API reference
- Create test suite โ Full coverage
- Benchmark performance โ Measure overhead
Project Comparison Table
| # | Project | Difficulty | Time | Key Skill | Fun |
|---|---|---|---|---|---|
| 1 | Safe String Library | โญโญ | 1 week | Bounds Checking | โญโญโญ |
| 2 | Integer Overflow Library | โญโญ | 1 week | Safe Arithmetic | โญโญโญ |
| 3 | Vulnerable Program Lab | โญโญ | 2 weeks | Vulnerability Classes | โญโญโญโญโญ |
| 4 | Stack Canary Implementation | โญโญโญ | 2 weeks | Exploit Defense | โญโญโญโญ |
| 5 | Format String Demonstrator | โญโญโญ | 2 weeks | Format Strings | โญโญโญโญโญ |
| 6 | Safe Memory Allocator | โญโญ | 1-2 weeks | Memory Safety | โญโญโญ |
| 7 | Bounds-Checking Arrays | โญโญ | 1-2 weeks | Array Safety | โญโญโญ |
| 8 | Heap Overflow Detector | โญโญโญ | 2 weeks | Heap Security | โญโญโญโญ |
| 9 | Input Validation Framework | โญโญ | 1-2 weeks | Input Handling | โญโญโญ |
| 10 | Return-to-libc Lab | โญโญโญ | 2-3 weeks | NX Bypass | โญโญโญโญโญ |
| 11 | Static Analysis Tool | โญโญโญ | 3-4 weeks | Code Analysis | โญโญโญโญ |
| 12 | Use-After-Free Demo | โญโญโญโญ | 3-4 weeks | Heap Exploitation | โญโญโญโญโญ |
| 13 | FORTIFY_SOURCE Impl | โญโญโญโญ | 2-3 weeks | Compiler Defenses | โญโญโญโญ |
| 14 | Secure Config Parser | โญโญ | 2 weeks | Secure Parsing | โญโญโญ |
| 15 | Complete Toolkit | โญโญโญโญ | 4-6 weeks | Integration | โญโญโญโญ |
Recommended Learning Path
Phase 1: Foundations (3-4 weeks)
Build secure coding fundamentals:
- Project 1: Safe String Library - Master bounded string operations
- Project 2: Integer Overflow Library - Prevent arithmetic bugs
- Project 6: Safe Memory Allocator - Secure dynamic memory
- Project 7: Bounds-Checking Arrays - Safe array access
Phase 2: Understanding Attacks (4-5 weeks)
Learn what youโre defending against:
- Project 3: Vulnerable Program Lab - See all vulnerability types
- Project 5: Format String Demonstrator - Deep format string understanding
- Project 10: Return-to-libc Lab - NX bypass techniques
Phase 3: Defense Mechanisms (4-5 weeks)
Implement real defenses:
- Project 4: Stack Canary Implementation - Compiler protection
- Project 8: Heap Overflow Detector - Runtime detection
- Project 13: FORTIFY_SOURCE Implementation - Compile-time protection
Phase 4: Practical Security (4-5 weeks)
Build usable tools:
- Project 9: Input Validation Framework - Secure input handling
- Project 14: Secure Config Parser - Real-world parsing
- Project 11: Static Analysis Tool - Find vulnerabilities
Phase 5: Advanced & Integration (6-8 weeks)
Master-level work:
- Project 12: Use-After-Free Demo - Advanced heap exploitation
- Project 15: Complete Toolkit - Professional-grade library
Summary
| # | Project | Main Language |
|---|---|---|
| 1 | Safe String Library | C |
| 2 | Integer Overflow Detection Library | C |
| 3 | Vulnerable Program Laboratory | C |
| 4 | Stack Canary Implementation | C/Assembly |
| 5 | Format String Vulnerability Demonstrator | C |
| 6 | Safe Memory Allocator Wrapper | C |
| 7 | Bounds-Checking Array Library | C |
| 8 | Heap Overflow Detector | C |
| 9 | Input Validation Framework | C |
| 10 | Return-to-libc Attack Lab | C/Python |
| 11 | Static Analysis Tool | Python |
| 12 | Use-After-Free Demonstrator | C |
| 13 | FORTIFY_SOURCE Implementation | C |
| 14 | Secure Configuration Parser | C |
| 15 | Complete Secure Coding Toolkit | C |
Resources
Essential Books
- โEffective C, 2nd Editionโ by Robert C. Seacord - Modern secure C
- โSecure Coding in C and C++โ by Robert C. Seacord - Comprehensive security reference
- โHacking: The Art of Exploitationโ by Jon Erickson - Attacker perspective
- โThe Shellcoderโs Handbookโ - Advanced exploitation
- โC Programming: A Modern Approachโ by K.N. King - C fundamentals
Standards & Guidelines
- CERT C Coding Standard: https://wiki.sei.cmu.edu/confluence/display/c
- CWE Top 25: https://cwe.mitre.org/top25/
- OWASP Secure Coding Practices: https://owasp.org/
Tools
- GCC Security Flags:
-fstack-protector,-D_FORTIFY_SOURCE=2,-pie - AddressSanitizer: Compile with
-fsanitize=address - Valgrind: Memory error detection
- AFL++: Fuzz testing
- pwntools: Exploit development
Practice Platforms
- picoCTF: https://picoctf.org/ - Beginner CTF
- pwnable.kr: https://pwnable.kr/ - Binary exploitation
- Exploit Education: https://exploit.education/ - Phoenix, Protostar
Total Estimated Time: 6-8 months of dedicated study
After completion: Youโll be able to write C code thatโs resistant to buffer overflows, integer overflows, format string attacks, and use-after-free vulnerabilities. More importantly, youโll understand why these attacks work, enabling you to audit code, find vulnerabilities, and design secure systems from the ground up.