Ongeïnitialiseerde Veranderlikes

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Basiese Inligting

Die kernidee hier is om te verstaan wat gebeur met ongeïnitialiseerde veranderlikes, aangesien hulle die waarde sal hê wat reeds in die toegewezen geheue aan hulle was. Voorbeeld:

  • Function 1: initializeVariable: Ons verklaar ’n veranderlike x en ken dit ’n waarde toe, byvoorbeeld 0x1234. Hierdie aksie is soortgelyk aan om ’n plekkie in geheue te reserveer en ’n spesifieke waarde daarin te plaas.
  • Function 2: useUninitializedVariable: Hier verklaar ons nog ’n veranderlike y maar ken geen waarde daaraan toe nie. In C word ongeïnitialiseerde veranderlikes nie outomaties op nul gestel nie. In plaas daarvan behou hulle watter waarde laas by hul geheueadres gestoor is.

Wanneer ons hierdie twee funksies opeenvolgend uitvoer:

  1. In initializeVariable word x ’n waarde toegekend (0x1234), wat ’n spesifieke geheueadres beset.
  2. In useUninitializedVariable word y verklaar maar nie ’n waarde daaraan toegekend nie, sodat dit die geheueplek reg ná x inneem. Omdat y nie geïnitialiseer is nie, neem dit uiteindelik die waarde oor van dieselfde geheueadres wat deur x gebruik is, omdat dit die laaste waarde was wat daar was.

Hierdie gedrag illustreer ’n sleutelkonsep in laevlakprogrammatuur: Geheubeheer is van kardinale belang, en ongeïnitialiseerde veranderlikes kan lei tot onvoorspelbare gedrag of sekuriteitskwesbaarhede, aangesien hulle per ongeluk sensitiewe inligting wat in die geheue agtergebly het, kan bevat.

Ongeïnitialiseerde stack-veranderlikes kan verskeie sekuriteitsrisiko’s inhou, soos:

  • Data Leakage: Sensitiewe inligting soos wagwoorde, enkripsiesleutels, of persoonlike besonderhede kan blootgestel word indien dit in ongeïnitialiseerde veranderlikes gestoor word, wat aanvallers moontlik toegang gee om hierdie data te lees.
  • Information Disclosure: Die inhoud van ongeïnitialiseerde veranderlikes kan besonderhede oor die program se geheue-uitsnit of interne werking openbaar, wat aanvallers help om geteikende exploits te ontwikkel.
  • Crashes and Instability: Operasies wat ongeïnitialiseerde veranderlikes betrek kan tot ongedefinieerde gedrag lei, wat programkrasies of onvoorspelbare resultate kan veroorsaak.
  • Arbitrary Code Execution: In sekere scenario’s kan aanvallers hierdie kwesbaarhede uitbuit om die program se uitvoertraject te verander, wat hulle in staat stel om arbitrêre kode uit te voer, wat moontlik remote code execution bedreigings kan insluit.

Voorbeeld

#include <stdio.h>

// Function to initialize and print a variable
void initializeAndPrint() {
int initializedVar = 100; // Initialize the variable
printf("Initialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&initializedVar, initializedVar);
}

// Function to demonstrate the behavior of an uninitialized variable
void demonstrateUninitializedVar() {
int uninitializedVar; // Declare but do not initialize
printf("Uninitialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&uninitializedVar, uninitializedVar);
}

int main() {
printf("Demonstrating Initialized vs. Uninitialized Variables in C\n\n");

// First, call the function that initializes its variable
initializeAndPrint();

// Then, call the function that has an uninitialized variable
demonstrateUninitializedVar();

return 0;
}

Hoe dit werk:

  • initializeAndPrint Function: Hierdie funksie verklaar ’n integer-variabele initializedVar, ken dit die waarde 100 toe, en druk dan beide die geheueadres en die waarde van die veranderlike uit. Hierdie stap is reguit en wys hoe ’n geïnitialiseerde veranderlike optree.
  • demonstrateUninitializedVar Function: In hierdie funksie verklaar ons ’n integer-variabele uninitializedVar sonder om dit te initialiseer. Wanneer ons probeer om die waarde te druk, kan die uitvoer ’n ewekansige getal wys. Hierdie getal verteenwoordig watter data ook al voorheen op daardie geheue-ligging was. Afhangend van die omgewing en die compilers kan die werklike uitvoer wissel, en soms kan sekere compilers veiligheidshalwe veranderlikes outomaties na nul initialiseer, hoewel daar nie op daardie gedrag staatgemaak moet word nie.
  • main Function: Die main funksie roep albei bogenoemde funksies in volgorde aan en demonstreer die kontras tussen ’n geïnitialiseerde veranderlike en ’n nie-geïnitialiseerde een.

Praktiese exploitation patrone (2024–2025)

Die klassieke “read-before-write” bug bly relevant omdat moderne mitigations (ASLR, canaries) dikwels op geheimhouding staatmaak. Typical attack surfaces:

  • Partially initialized structs copied to userland: Kernel or drivers frequently memset only a length field and then copy_to_user(&u, &local_struct, sizeof(local_struct)). Padding and unused fields leak stack canary halves, saved frame pointers or kernel pointers. If the struct contains a function pointer, leaving it uninitialized may also allow controlled overwrite when later reused.
  • Uninitialized stack buffers reused as indexes/lengths: An uninitialized size_t len; used to bound read(fd, buf, len) may give attackers out-of-bounds reads/writes or allow bypassing size checks when the stack slot still contains a large value from a prior call.
  • Compiler-added padding: Selfs wanneer individuele lede geïnitialiseer is, word implisiete padding-bye tussen hulle nie geïnitialiseer nie. Om die hele struct na userland te kopieer leak padding wat dikwels vorige stack-inhoud bevat (canaries, pointers).
  • ROP/Canary disclosure: As ’n funksie ’n plaaslike struct na stdout kopieer vir debugging, kan nie-geïnitialiseerde padding die stack canary openbaar wat daaropvolgende stack overflow exploitation sonder brute-force moontlik maak.

Minimale PoC-patroon om sulke kwessies tydens hersiening op te spoor:

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));
// later debug helper
write(1, &m, sizeof(m));   // leaks padding + stale stack
return m.len;
}

Mitigations & compiler options (keep in mind when bypassing)

  • Clang/GCC auto-init: Recent toolchains expose -ftrivial-auto-var-init=zero or -ftrivial-auto-var-init=pattern, filling every automatic (stack) variable at function entry with zeros or a poison pattern (0xAA / 0xFE). Dit sluit die meeste uninitialized-stack info leaks en maak eksploitasiemoontlikhede moeiliker deur geheime in bekende waardes te verander.
  • Linux kernel hardening: Kernels gebou met CONFIG_INIT_STACK_ALL of die nuwer CONFIG_INIT_STACK_ALL_PATTERN zero/pattern-initialise elke stack-slot by funksie-ingang, envee canaries/pointers wat andersins sou leak. Soek na distros wat Clang-built kernels met hierdie opsies verskaf (algemeen in 6.8+ hardening configs).
  • Opt-out attributes: Clang laat nou __attribute__((uninitialized)) op spesifieke locals/structs toe om performance-kritieke areas oningestel te hou selfs wanneer globale auto-init geaktiveer is. Hersien sulke annotasies noukeurig — hulle merk dikwels opsetlike aanval-oppervlakke vir side channels.

Vanuit ’n aanvaller se perspektief bepaal die kennis of die binêre met hierdie vlae gebou is of stack-leak primitives lewensvatbaar is, of dat jy moet skuif na heap/data-section disclosures.

Finding uninitialized-stack bugs quickly

  • Compiler diagnostics: Build with -Wall -Wextra -Wuninitialized (GCC/Clang). Vir C++-kode sal clang-tidy -checks=cppcoreguidelines-init-variables baie gevalle outomaties na zero-init regstel en is handig om gemiste locals tydens ’n oudit te identifiseer.
  • Dynamic tools: -fsanitize=memory (MSan) in Clang of Valgrind se --track-origins=yes dui betroubaar lees van oningestelde stack-bytte tydens fuzzing aan. Instrumenteer toets-harnasse met hierdie gereedskap om subtiele padding leaks aan die lig te bring.
  • Grepping patterns: In revisies soek na copy_to_user / write oproepe van hele structs, of memcpy/send van stack-data waar slegs ’n deel van die struct gestel is. Gee spesiale aandag aan foutpaaie waar initialisering oorgeslaan word.

ARM64 Example

Dit verander glad nie in ARM64 nie aangesien plaaslike veranderlikes ook op die stack bestuur word; jy kan check this example waar dit getoon word.

References

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks