Hacktricks-skills uninitialized-variable-analysis
Analyze C code for uninitialized stack variable vulnerabilities, detect information disclosure risks, and provide exploitation or mitigation guidance. Use this skill whenever the user mentions uninitialized variables, stack variables, C security, memory leaks, info disclosure, binary exploitation, or asks about analyzing C code for security vulnerabilities. Make sure to use this skill when reviewing C code for security issues, even if the user doesn't explicitly mention 'uninitialized' - partial struct initialization, copy_to_user calls, and stack buffer issues often indicate this vulnerability class.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/binary-exploitation/stack-overflow/uninitialized-variables/SKILL.MDUninitialized Variable Analysis
A skill for identifying, analyzing, and exploiting uninitialized stack variable vulnerabilities in C code.
When to Use This Skill
Trigger this skill when:
- User asks about uninitialized variables in C
- User wants to analyze C code for security vulnerabilities
- User mentions stack variables, memory disclosure, or info leaks
- User is doing binary exploitation research
- User asks about compiler flags related to stack initialization
- User wants to understand how uninitialized variables can be exploited
- User is reviewing kernel/driver code for security issues
Core Concepts
What Are Uninitialized Variables?
Uninitialized stack variables contain whatever data was previously at that memory location. They don't automatically get zeroed out, which means they can leak sensitive information or be exploited to control program behavior.
Key insight: When you declare
int x; without initialization, x contains whatever bytes were last written to that stack slot - potentially sensitive data from previous function calls.
Security Risks
- Data Leakage: Sensitive information (passwords, keys, personal data) can be exposed
- Information Disclosure: Memory layout details can aid attackers in developing exploits
- Crashes and Instability: Undefined behavior from uninitialized data
- Arbitrary Code Execution: In some cases, can lead to ROP or function pointer overwrites
Detection Patterns
Code Review Patterns
Look for these patterns in C code:
// Pattern 1: Partial struct initialization struct msg { char data[0x20]; uint32_t len; }; ssize_t handler(int fd) { struct msg m; // never fully initialized m.len = read(fd, m.data, sizeof(m.data)); write(1, &m, sizeof(m)); // leaks padding + stale stack return m.len; }
Red flags:
- Struct declared but only some fields initialized
,copy_to_user
, orwrite
of entire structmemcpy- Debug helpers that print local structs
- Error paths where initialization is skipped
Compiler Diagnostics
Build with these flags to catch issues:
# GCC/Clang warnings gcc -Wall -Wextra -Wuninitialized program.c clang -Wall -Wextra -Wuninitialized program.c # C++ specific clang-tidy -checks=cppcoreguidelines-init-variables
Dynamic Analysis Tools
- MemorySanitizer (MSan):
clang -fsanitize=memory program.c - Valgrind:
valgrind --track-origins=yes ./program
These tools reliably flag reads of uninitialized stack bytes during execution.
Exploitation Patterns
Classic Read-Before-Write
When a struct is partially initialized and then copied to userland:
- Identify the struct - Look for structs with padding or unused fields
- Find the leak - Look for
,copy_to_user
, orwrite
of the whole structmemcpy - Determine what's leaked - Stack canaries, saved frame pointers, kernel pointers
- Plan the exploit - Use leaked info to bypass ASLR or canaries
Practical Attack Surfaces (2024-2025)
- Partially initialized structs: Kernel/driver code that
only length fieldsmemset - Uninitialized indexes/lengths:
used to bound reads/writessize_t len; - Compiler padding: Even when members are initialized, padding bytes aren't
- Debug helpers: Functions that copy local structs to stdout for debugging
- ROP/Canary disclosure: Uninitialized padding can reveal stack canaries
Minimal PoC Pattern
struct msg { char data[0x20]; uint32_t len; }; ssize_t handler(int fd) { struct msg m; // never fully initialized m.len = read(fd, m.data, sizeof(m.data)); write(1, &m, sizeof(m)); // leaks padding + stale stack return m.len; }
Mitigations
Compiler Options
-
Clang/GCC:
or-ftrivial-auto-var-init=zero-ftrivial-auto-var-init=pattern- Fills every automatic (stack) variable with zeros or poison pattern (0xAA / 0xFE)
- Closes most uninitialized-stack info leaks
-
Linux kernel:
orCONFIG_INIT_STACK_ALLCONFIG_INIT_STACK_ALL_PATTERN- Zero/pattern-initialize every stack slot at function entry
- Common in 6.8+ hardening configs
Code Fixes
// Bad struct msg m; m.len = read(fd, m.data, sizeof(m.data)); // Good - zero-initialize entire struct struct msg m = {0}; m.len = read(fd, m.data, sizeof(m.data)); // Or explicit initialization struct msg m; memset(&m, 0, sizeof(m)); m.len = read(fd, m.data, sizeof(m.data));
Opt-out Attributes (Watch for These)
Clang allows
__attribute__((uninitialized)) on specific locals/structs to keep performance-critical areas uninitialized. Review such annotations carefully - they often mark deliberate attack surface.
Analysis Workflow
When analyzing code for uninitialized variable vulnerabilities:
- Identify stack variables - Look for local variables in functions
- Check initialization - Verify all fields are initialized before use
- Find disclosure points - Look for
,copy_to_user
,write
of structsmemcpy - Assess impact - Determine what sensitive data could leak
- Recommend fixes - Suggest proper initialization or compiler flags
Example Analysis
Input
struct request { char buffer[64]; int flags; void (*callback)(void); }; void process_request(int fd) { struct request req; req.flags = read(fd, req.buffer, sizeof(req.buffer)); send_response(fd, &req, sizeof(req)); }
Analysis Output
Vulnerability Found: Uninitialized stack variable
Location:
process_request() function
Issue:
req struct is not fully initialized before being sent
Leaked Data:
(function pointer) - 8 bytesreq.callback- Padding between
andbuffer
- 4 bytesflags - Padding between
andflags
- 4 bytescallback
Impact: Information disclosure of stack contents, potential ROP chain construction
Fix:
void process_request(int fd) { struct request req = {0}; // Zero-initialize req.flags = read(fd, req.buffer, sizeof(req.buffer)); send_response(fd, &req, sizeof(req)); }
ARM64 Considerations
Uninitialized variable vulnerabilities work the same on ARM64 - local variables are still managed on the stack. The exploitation patterns and mitigations are identical to x86/x64.