Secure coding in C: common mistakes
You learn, from the defender’s side, the C mistakes that become vulnerabilities, catch them in code review and prevent them with compiler protections and fuzzing.
Level 401 · 21 lessons · 18 practice labs
Lessons
Memory safety mistakes
- Stack buffer overflow: the cost of unbounded copying
- Writing one too many: off-by-one and the terminator
- Heap overflow and corrupted neighbouring data
- Use after free
- Uninitialised memory and information leaks
- Short task: flag memory bugs in a code review
Logic and type mistakes
- Integer wraparound and an undersized buffer
- Signed and unsigned comparison traps
- Format string bugs and %n
- Check-then-use races: access and open
- Trusting environment variables and PATH
- Command injection through system() and popen
- Short task: review a privileged helper program
Prevention and verification
- Choosing safe APIs and a banned-function list
- Compiler protections: FORTIFY_SOURCE, stack protector, PIE
- Fuzzing a parser with libFuzzer
- Black-box fuzzing with AFL++
- Triaging crashes: minimising and root cause
- A secure code review checklist and writing a bug report
- Short task: fix the bug the fuzzer found
Capstone
- Capstone: audit, fix and fuzz an unsafe parser
Practice labs
- Closing an overflow in a greeting function: Make a function that strcpy's the user name into a fixed buffer bounds-checked and test it with long names.
- Making room for the terminator: Fix code that forgets the \0 after strncpy and overruns by one byte so ASan reports clean.
- A heap overflow that corrupts a neighbour: Find the code that writes past a note field and corrupts the permission flag next to it, fix it with a bounds check and add a regression test.
- Use after free in a session object: Fix code that keeps a pointer to a logged-out session by applying ownership rules so ASan and the tests pass.
- An information leak from uninitialised memory: Find where a reply struct is sent with its padding bytes and close the leak with memset and field-by-field writes.
- Catching wraparound in a length sum: Add an overflow check to code that adds two lengths and allocates, passing the boundary tests.
- The signed-unsigned comparison trap: Fix code where a length of -1 turns into a huge number and slips past a check, and clear the -Wsign-compare warnings.
- Closing a format string in an audit log: Fix audit code that passes user input to syslog as the format and confirm it with -Wformat-security.
- Finding a narrowing conversion: Fix a parser that stores a size_t length in an unsigned short and allocates a small buffer, testing with huge inputs.
- Closing the access-then-open race: Rewrite code that checks with access and then calls open using O_NOFOLLOW and an fstat check.
- Replacing system() with execv: Rewrite a backup helper that passes a file name to the shell via system() using fork and execv so names with ; and $() stay harmless.
- Cleaning the environment in a privileged helper: Make a privileged helper that trusts PATH and LD_ variables set up a safe environment and use full paths.
- Reviewing code that uses popen: Review a diagnostic tool that runs user input through popen, report the risks and apply a shell-free fix.
- Enforcing a banned-function list: Ban gets, strcpy and sprintf in a project with a header that fails the build and replace the remaining calls.
- Seeing the effect of protection flags: Build the same overflowing program with _FORTIFY_SOURCE and the stack protector and compare and report the runtime reaction.
- Fuzzing a date parser with libFuzzer: Write a libFuzzer target for a date parser, run it with ASan and fix the first bug it finds.
- Triaging AFL++ crashes: Minimise ten crashes AFL++ found, group those with the same root cause and write a short bug report for each group.
- A code review with a checklist: Review Poyrazlı Enerji's meter-reading module with a secure code checklist and fix the two bugs you find with tests.
About this course
You learn, from the defender’s side, the C mistakes that become vulnerabilities, catch them in code review and prevent them with compiler protections and fuzzing.
What you will learn
- Memory safety mistakes
- Logic and type mistakes
- Prevention and verification
- Capstone
Prerequisites
You should have practised the topics of the same path up to level 301.
Lab environment
Lessons run in your own Kali Linux terminal that opens in the browser. Nothing to install; the lab starts clean in every lesson.
Frequently asked questions
- Is this course right for my level?
- The course is at level 401; it assumes you know the topics of the lower-level courses.
- Is there anything to install?
- No. Every lesson runs in your own lab environment that opens in the browser.
- How do lessons work?
- Each lesson has 8 to 10 steps and a short quiz. Early steps show the command to type, later steps give less help; if two attempts fail, the solution opens.
- Can I try it for free?
- Yes. The first three lessons of every course are free.