![[de auteurs]](../../common/images/FredCrisBCrisG.jpg) 
 
Original in fr Frédéric Raynal, Christophe Blaess, Christophe Grenier
fr to en Georges Tarbouriech
en to nl Hendrik-Jan Heins
Christophe Blaess is een onafhankelijke luchtvaart ingenieur. Hij is een Linux fan en werkt veel met dit systeem. Hij coördineert de vertaling van de man pages zoals die te vinden zijn op de site van het Linux Documentation Project.
Christophe Grenier is een 5e jaars student aan de ESIEA, hij werkt daar ook als systeembeheerder. Hij is gek van computer beveiligingssystemen.
Frédéric Raynal gebruikt Linux, gecertificeerd zonder enige vorm van patent. Maar iets geheel anders: je moet echt Dancer in the Dark gaan zien: behalve Björk die geweldig is, moet deze film je wel raken (Ik kan niet meer zeggen zonder het einde weg te geven, maar het is zowel tragisch als fantastisch).
Dit artikel is het eerste in een serie over de voornaamste typen veiligheidslekken in applicaties. We zullen laten zien hoe ze vermeden kunnen worden door je ontwikkelgewoontes enigzins te veranderen.
![[article illustartion]](../../common/images/illustration182.gif) 
Het duurt over het algemeen niet langer dan 2 weken voordat er in een belangrijke applicatie die onderdeel is van de meeste Linux applicaties een veiligheidslek gevonden is, zoals bijvoorbeeld een gat waardoor een locale gebruiker root kan worden. Ondanks de hoge kwaliteit van het grootste deel van deze software, is het lastig om de veiligheid van een programma te garanderen: de software moet zodanig ontwikkeld zijn dat een inbreker niet op een legale manier gebruik kan maken van systeembronnen. De beschikbaarheid van de broncode van applicaties is hierbij een grote hulp, en wordt als zodanig ook gewaardeerd door programmeurs, maar het nadeel hiervan is dat de kleinste foutjes in de software voor iedereen zichtbaar worden. Bovendien worden deze defecten toevallig aangetroffen en de mensen die deze defecten aantreffen, hebben niet altijd de beste bedoelingen.
Voor de systeembeheerder betekent dit dat zijn dagelijks werk bestaat uit 
het lezen van de lijsten met bekende veiligheidsproblemen en het onmiddelijk 
updaten van de betreffende pakketten. Voor een programmeur kunnen deze 
veiligheidslekken een goede oefening zijn om deze veiligheidslekken uit te 
proberen, aangezien het beter is om veiligheidslekken te vermijden bij het 
programmeren, zodat ze ook later niet gedicht hoeven te worden. We zullen 
proberen enkele "klassieke" gevaarlijke gedragingen te definiëren en oplossingen geven om de risico's te beperken. We gaan het niet hebben over
netwerkbeveiligings-problemen, aangezien die vaak het gevolg van problemen 
met de configuratie zijn (gevaarlijke cgi-bin scripts, ...) of van systeembugs 
die DOS (Denial Of Service) type aanvallen toelaten en aldus ervoor 
zorgen dat een machine niet meer luistert naar de eigen clienten. Dit type 
probleem is de zorg van de systeembeheerder of de kernel-ontwikkelaars. Maar 
de applicatie-programmeur moet ook z'n eigen code beschermen zodra hij externe 
gegevens gaat gebruiken. Sommige versies van pine, 
acroread, netscape, access,...
stonden toegang met meer rechten toe of hadden onder sommige omstandigheden 
last van informatie lekken. Dus eigenlijk is veilig programmeren 
ieders zorg.
Deze serie artikelen laat methodes zien die gebruikt kunnen worden om een Unix systeem te beschadigen. We hadden ze ook alleen kunnen noemen of er slechts enkele woorden aankunnen wijden, maar we prefereren de complete uitleg om mensen de risico's te laten begrijpen. Dus, als je een programma "debugged" of je eigen programma ontwikkelt, kan je nu deze fouten vermijden of verbeteren. We gaan ieder veiligheidslek op dezelfde manier benaderen. We gaan beginnen met de details omtrend de manier waarop het werkt, daarna laten we zien hoe ze te vermijden zijn.Bij ieder voorbeeld zullen we gebruik maken van veiligheidslekken die ook nu nog in veel gebruikte software voorkomen.
Dit eerste artikel gaat over de basiskennis die benodigd is om
   veiligheidslekken te begrijpen, daarom gaat het vooral over
   privileges en de Set-UID of de Set-GID bit.
   Daarna gaan we de gaten die gebaseerd zijn op de system()
   functie analyseren, omdat deze makkelijker te begrijpen zijn.
We zullen veel gebruik maken van kleine C programmaatjes om dat
   waarover we praten te illustreren. De aanpakken die in deze reeks
   artikelen worden genoemd zijn echter ook van toepassing op andere
   programmeertalen, zoals java, perl, commandoregelscripts....
   Sommige veiligheidslekken zijn afhankelijk van de gebruikte taal,
   maar dit geldt niet voor alle veiligheidslekken zoals we zullen
   zien met system().
op een Unix systeem zijn gebruikers niet gelijk aan elkaar, en ook
   applicaties zijn dat niet. De toegang tot de bestandssysteem-nodes
   en daarmee de randapparatuur vertrouwt op een stricte identiteits-
   check. Sommige gebruikers mogen gevoelige operaties uitvoeren om
   het systeem te onderhouden. Een getal genaamd UID (User Identifier)
   staat identificatie toe. Om dit wat eenvoudiger te maken correspondeert
   dit nummer met een gebruikersnaam, hierbij wordt deze associatie gelegd
   in het /etc/passwd bestand.
De UID 0, met de standaardnaam root, heeft overal in
   het systeem toegang. Hij kan systeemnodes aanleggen, veranderen
   verwijderen, maar hij kan ook de fysieke configuratie van de
   machine beheren, partities "mounten", netwerkconnecties activeren
   en de bijbehorende configuratie veranderen (bijvoorbeeld het IP-adres),
   of gebruik maken van systeemaanroepen zoals mlock() om
   fysiek geheugen te veranderen, of sched_setscheduler() om
   het volgorde-mechanisme te veranderen. In een nog te schrijven artikel
   zullen we de Posix.1e features gaan bestuderen die ons toestaan om de
   privileges van een applicatie die draait als root te beperken,
   maar voor nu gaan we er vanuit dat de "super-user" alles kan op een
   machine.
De aanvallen die we zullen noemen, zijn interne aanvallen hierbij gaat het dus om een geautoriseerde gebruiker die op een machine privileges probeert te verkrijgen die hij niet heeft. Netwerkaanvallen zijn externe aanvallen die komen van mensen die proberen een verbinding te leggen met een machine waarop ze geen toegang hebben.
Om gebruik te maken van privileges die gereserveerd zijn voor een andere gebruiker zonder dat er ingelogd kan worden onder de identiteit van die gebruiker, moet iemand tenminste de mogelijkheid hebben om te communiceren met een applicatie onder het UID van het slachtoffer. Als een applicatie, een proces, onder Linux draait, heeft het een strak gedefinieerde identiteit. Allereerst heeft een programma een attribuut dat een RUID (Real UID) genoemd, dat correspondeert met de ID van de gebruiker die het programma gestart heeft. Deze gegevens worden beheerd door de kernel en kunnen over het algemeen niet veranderd worden. een tweede attribuut completeert deze informatie: het EUID veld (Effective UID) dat correspondeert met de identiteit die de kernel aanneemt bij het beheren van de toegangsrechten (het openenen van bestanden, gereserveerde systeemaanroepen).
De privileges van een andere gebruiker aannemen betekent dat alles uitgevoerd zal worden onder de UID van die gebruiker en niet onder de "correcte", eigen UID. Een cracker probeert natuurlijk de root ID te verkrijgen, maar veel andere gebruikers-accounts zijn ook interessant, hetzij doordat zij toegang geven to systeem- gegevens (news, mail, lp...) hetzij doordat ze het lezen van prive-gegevens toestaan (mail, personal files, etc) of omdat ze gebruikt kunnen worden om illegale activiteiten zoals aanvallen op andere sites kunnen maskeren.
Om een applicatie te draaien met de privileges van een effectieve UID
   die anders is dan z'n echte UID (de gebruiker die hem gestart heeft), moet
   het uitvoerbare bestand een specifieke bit hebben die aan staat en Set-UID
   heet. deze bit kan gevonden worden in het bestandstoegangsattribuut (evenals
   de bits die de uitvoerbaarheid, schrijfbaarheid bits, groepsleden en andere
   toegangsrechten bevat) en hij heeft de octale waarde 4000. De Set-UID bit 
   wordt gerepresenteerd door een s als de rechten met een 
   ls commando worden opgevraagd:
Het commando ">> ls -l /bin/su -rwsr-xr-x 1 root root 14124 Aug 18 1999 /bin/su >>
find / -type f -perm +4000" geeft een
    lijst van de systeemapplicaties weer met hun Set-UID bit ingesteld
    op 1. Wanneer de kernel een applicatie draait met de Set-UID bit in de
    aan-stand, maakt hij gebruik van de identiteit van de programma-eigenaar
    als EUID voor het proces. De RUID aan de andere kant, verandert niet en
    correspondeert met de gebruiker die het programma startte. Iedere gebruiker
    heeft bijvoorbeeld toegang tot het /bin/su commando, maar het
    commando draait onder de identiteit van z'n eigenaar (root) met 
    alle privileges die op het systeem aanwezig zijn.. Het moge duidelijk zijn 
    dat de programmeur zeer voorzichtig moet zijn als hij een programma schrijft
    dat dit attribuut bevat.
Ieder proces heeft ook een effectief groeps-ID, EGID, en een echte
   identifier met de RGID. De Set-GID bit (2000 in octalen) in de toegangs
   rechten van een uitvoerbaar bestand, vraagt de kernel om de groep waartoe
   de applicatie behoort als EGID en niet de GID van de gebruiker die het
   programma gestart heeft. Een vreemde combinatie verschijnt soms wanneer de
   Set-GID op 1 staat, maar zonder de groepsuitvoer bit. Dit is eigenlijk een
   conventie die niets te maken heeft met privileges in relatie tot applicaties,
   maar dit geeft aan dat het bestand geblokkeerd kan worden met de functie
   fcntl(fd, F_SETLK, lock). Normaal gesproken maakt
   een applicatie geen gebruik van de Set-GID bit, maar soms gebeurt het wel.
   Enkele spelletjes bijvoorbeeld gebruiken het om de beste scores in een
   systeemdirectory te bewaren.
Er zijn verschillende typen aanvallen tegen een systeem. Vandaag zullen we de mechanismen om een extern commando uit te voeren vanuit een applicatie bestuderen. Dit is meestal een commandoregel die draait onder de identiteit van de eigenaar van de applicatie. Een tweede type aanval vertrouwt op de buffer overflow die de aanvaller de mogelijkheid geeft om persoonlijke code instructies te geven. En tenslotte is de derde belangrijke aanvalsmethode is gebaseerd op race condition - een "tijdsgat" tussen twee instructies waarin een systeemcomponent wordt veranderd (normaal gesproken is dat een bestand), terwijl de applicatie denkt dat er niets veranderd is.
De eerste twee aanvalstypes proberen meestal een commandoregel uit
   te voeren met de privileges van de eigenaar van de applicatie, terwijl
   de derde in plaats daarvan is gericht op het verkrijgen van schrijftoegang
   naar beschermde systeembestanden. Leestoegang wordt soms gezien als een
   zwakte in de systeembeveiliging (persoonlijke bestanden, emails, password
   bestand /etc/shadow, en pseudo kernel configuratiebestanden
   in /proc).
De doelen van aanvallen op de systeembeveiliging zijn over het algemeen
   programma's die een Set-UID (of Set-GID) bit aan hebben staan. Dit heeft
   echter ook effect op alle applicaties die draaien onder een andere ID dan
   die van z'n eigen gebruiker. De systeem daemons vertegenwoordigen een grote
   groep van dit type programma's. Een daemon is een applicatie die over het
   algemeen tijdens het opstarten wortd gestart en draait op de achtergrond 
   zonder enige controle terminal en die gepriviligeerd werk voor alle 
   gebruikers doet.  Bijvoorbeeld de lpd daemon, die alle 
   gebruikers toestaat om documenten naar de printer te sturen, 
   sendmail verstuurt en her-adresseert e-mail, of 
   apmd vraagt de Bios voor de status van de battery van een 
   notebook. Sommige daemons beheren de communicatie met externe gebruikers via 
   het netwerk (Ftp, Http, Telnet... services). Een service die 
   inetd heet beheert de connecties voor veel van deze services.
   
We kunnen nu concluderen dat een programma aangevallen kan worden zodra het communiceert, hoe kort ook, met een gebruiker die niet dezelfde is als degene die het programma gestart heeft. Als je dit type applicatie ontwikkelt, moet je vooral op de risico's letten die de functies die we hier bestuderen met zich meebrengen.
Wanneer een applicatie draait met een EUID die anders is dan z'n RUID, dan is dat om de gebruiker privileges te geven die hij nodig heeft, maar zelf niet heeft (bestandstoegang, gereserveerde systeemaanroepen...). Deze privileges zijn echter maar korte tijd nodig, bijvoorbeeld voor het openen van een bestand, afgezien daarvan kan de applicatie draaien onder de gebruikersprivileges, Het is mogelijk om tijdelijk de EUID van een applicatie te veranderen met behulp van een systeemaanroep:
int seteuid (uid_t uid);Een proces kan z'n EUID altijd veranderen en het een RUID geven. In dat geval wordt de oude UID bewaard in een veld genaamd SUID (Saved UID) anders dan SID (Session ID) gebruikt voor controle terminal beheer.Het is altijd mogelijk om de SUID terug te krijgen en te gebruiken als EUID. Natuurlijk kan een programma dat een null EUID heeft (root) wanneer hij dat wil zowel z'n EUID en RUID veranderen (dit is hoe
/bin/su werkt).
Om de risico's van een aanval te verkleinen, wordt voorgesteld om de EUID te veranderen en de RUID van de gebruikers in plaats daarvan te gebruiken. Wanneer een deel van de code privileges nodig heeft die corresponderen met die van de bestandseigenaar, is het mogelijk om de bewaarde UID in de EUID te zetten. Hier is een voorbeeld:
  uid_t e_uid_initial;
  uid_t r_uid;
  int
  main (int argc, char * argv [])
  {
    /* bewaart de verschillende UIDs */
    e_uid_initial = geteuid ();
    r_uid = getuid ();
    /* limiteert de toegangsrechten tot die van de
     * gebruiker die het programma start */
    seteuid (r_uid);
    ...
    privileged_function ();
    ...
  }
  void
  privileged_function (void)
  {
    /* Krijgt de initiële privileges terug */
    seteuid (e_uid_initial);
    ...
    /* Deel dat de privilegs nodig heeft */
    ...
    /* Terug naar de rechten van degene die het programma heeft gestart */
    seteuid (r_uid);
  }
Deze methode is veiliger dan de, helaas, veel gebruikte methode waarbij de initiële EUID wordt gebruikt en dat deze tijdens een "risicovolle operatie" tijdelijk gereduceerde privileges krijgt. Deze reductie in privileges is echter waardeloos tegen buffer-overflow aanvallen. Zoals we in het volgende artikel zullen zien, willen deze aanvallen de applicatie vragen een persoonlijke instructie uit te voeren en deze kan systeemaanroepen bevatten die nodig zijn om het privilegeniveau te verhogen. Maar ondanks dat beschermt deze aanpak tegen externe commando's van de meeste race conditions.
Een applicatie moet vaak een externe systeemfunctie aanroepen. Een
   bekend voorbeeld betreft het mail commando dat e-mail
   beheert (het draaien van rapporten, alarmfunctie, statistiek etc.)
   dit alles zonder dat er een complexe dialoog met het mail systeem
   bestaat. De eenvoudigste oplossing is gebruik maken van de
   bibliotheekfunctie:
int system (const char * command)
Deze functie is vrij gevaarlijk: hij roept de commandoregel aan om
   het commando dat gegeven is als argument uit te voeren. Het gedrag van
   de commandoregel hangt af van de keuzes van de gebruiker. Een typisch
   voorbeeld komt van de PATH omgevingsvariabele.
   Laten we eens kijken naar een applicatie die de mail
   functie aanroept. Bijvoorbeeld het nu volgende programma dat z'n broncode
   naar de gebruiker die het starttte stuurt:
/* system1.c */
#include <stdio.h>
#include <stdlib.h>
int
main (void)
{
  if (system ("mail $USER < system1.c") != 0)
    perror ("system");
  return (0);
}
Laten we zeggen dat het programma Set-UID root  is:
Om dit programma uit te voeren, draait het systeem een commandoregel (met>> cc system1.c -o system1 >> su Password: [root] chown root.root system1 [root] chmod +s system1 [root] exit >> ls -l system1 -rwsrwsr-x 1 root root 11831 Oct 16 17:25 system1 >>
/bin/sh) en met de optie -c, het geeft
    hem de uit te voeren instructie. Daarna gaat de commandoregel door de
    directoryboom volgens de PATH omgevingsvariabele om een
    uitvoerbaar bestand te vinden dat mail heet. Om het programma
    te compromiteren, hoeft de gebruiker alleen maar de inhoud van de variabelen
    te veranderen voor het draaien van de applicatie. Bijvoorbeeld:
Zoekt naar het>> export PATH=. >> ./system1
mail commando, maar alleen binnen de huidige
    directory. Er hoeft nu alleen maar een uitvoerbaar bestand worden gemaakt
    (bijvoorbeeld een script dat een nieuwe commandoregel start) en noem het
    mail en het programma zal nu uitgevoerd worden met de EUID
    van de eigenaar van de hoofdapplicatie! Hier draait ons script
    /bin/sh. Echter, doordat het is uitgevoerd met een 
    doorgestuurde standaard input ( net als het initiële mail 
    commando), we moeten het terug in de terminal zien te krijgen. Daarom maken
    we nu het volgende script:
Hier is het resultaat:#! /bin/sh # "mail" script draait een commandoregel # en krijgt de standaardinput terug. /bin/sh < /dev/tty
>> export PATH="." >> ./system1 bash# /usr/bin/whoami root bash#
Deze eerste oplossing bestaat er natuurlijk uit dat de volledige
   padnaam van het programma wordt gegeven, bijvoorbeeld
   /bin/mail. Hierdoor verschijnt er een nieuw probleem:
   de applicatie vertrouwt op de systeeminstallatie. Een applicatie
   als /bin/mail is normaal gesproken op ieder systeem
   beschikbaar, maar is bijvoorbeeld GhostScript? (staat het in
   /usr/bin, /usr/share/bin,
   /usr/local/bin ?). Een ander type aanval wordt mogelijk
   met enkele oude commanodoregels: het gebruik van de omgevingsvariabele
   IFS. De commandoregel gebruikt deze om de woorden in de
   commandoregel te ontleden. Deze variabele bevat de afscheiders. De
   standaardwaardes hiervoor zijn de spatie, tab en return. Als de gebruiker
   de slash toevoegt /, begrijpt de commandoregel het commandos
   "/bin/mail" als "bin mail". Een uitvoerbaar bestand
   geheten bin in de huidige directory kan nu worden uitgevoerd 
   door PATH in te stellen, precies zoals we eerder al zagen, en 
   het staat toe om het programma te draaien met de EUID van de hoofdapplicatie.
Onder Linux is de IFS omgevingsvariabele geen probleem meer, 
omdat bash en pdksh hem beiden met de standaard karakters uitvoeren tijdens het
opstarten.  Maar omdat je aan de portabiliteit van de applicatie moeten denken,
moet je erop letten dat sommige systemen minder veilig zijn met deze variabele.
Enkele andere omgevingsvariabelen kunnen onverwachte problemen veroorzaken.
   Bijvoorbeeld de mail applicatie, deze staat gebruikers toe om 
   een commando te draaien terwijl ze een bericht samenstellen door middel van
   een escape sequentie "~!". Als de gebruiker de string 
   "~!commando" aan het begin van de regels schrijft, 
   wordt het commando uitgevoerd. Het programma /usr/bin/suidperl 
   wordt gebruikt om perl scripts uit te voeren met een Set-UID bit aanroep 
   /bin/mail om een bericht naar de root te sturen als het
   een probleem vindt. Aangezien /bin/mail een Set-UID 
   root, aanroep is, wordt /bin/mail uitgevoerd met root 
   privileges en bevat het de naam van het "beschadigde" bestand. 
   
   Een gebruiker kan nu een bestand maken met een naam die een "carriage return"
   gevolgd door een ~!command sequence en nog een "carriage return"
   bevat. Als een perl script dat suidperl aanroept faalt op een 
   "low-level" probleem dat gerelateerd is aan dit bestand, wordt er een bericht
   gestuurd onder de identiteit van de root dat de escape sequence van 
   de mail applicatie bevat en het commando in de bestandsnaam 
   wordt uitgevoerd met root privileges.
Dit probleem zou niet moeten bestaan, aagezien het mail 
programma geen escape sequences zou moeten mogen accepteren wanneer deze 
automatisch worden gedraaid (dus niet vanaf een terminal). Helaas staat een 
ongedocumenteerde "feature" van deze applicatie (waarschijnlijk voor debuggen),
deze escape sequence toe zodra de omgevingsvariabele interactive is
aangezet. Het resultaat?  Een veiligheidslek dat eenvoudig geëxploiteerd 
kan worden (en dat gebeurt dus ook) in een applicatie die de systeemveiligheid
zou moeten verbeteren. De schuld moet gedeeld worden. Allereerst bevat 
/bin/mail een ongedocumenteerde optie die vooral gevaarlijk is 
omdat het code-uitvoering toestaat terwijl het alleen de verzonden data
controleert, wat a priori verdacht zou zijn voor een mail applicatie
   Ten tweede, zelfs wanneer de /usr/bin/suidperl ontwikkelaars 
zich niet bewust waren van de interactieve variabele, zouden ze de
uitvoerbare omgeving niet moeten hebben laten zoals hij was wanneer er een 
extern commando werd aangeroepen, vooral niet wanneer dit programma schrijft 
als Set-UID root.
Eigenlijk negeert Linux de Set-UID en Set-GID bit wanneer scripts uitgevoerd
worden (lees /usr/src/linux/fs/binfmt_script.c en 
/usr/src/linux/fs/exec.c). Maar sommige trucs staan je toe om deze 
regel over te slaan, zoals Perl doet met z'n eigen scripts door gebruik te maken
van /usr/bin/suidperl om deze bits ook in aanmerking te nemen.
Het is niet altijd eenvoudig om een vervanger te vinden voor de 
system() functie.  De eerste variant is gebruik maken van systeem 
aanroepen zoals execl() of execle(). Echter, dit zal 
heel anders werken, aangezien een extern programma niet langer aangeroepen wordt
als een subroutine, maar in plaats daarvan worden de commando's aangeroepen in 
plaats van het al draaiende proces. Je moet het proces dus splitsen en de
commandoregel argumenten ontleden. Vandaar het volgende programma:
  if (system ("/bin/lpr -Plisting stats.txt") != 0) {
    perror ("Printing");
    return (-1);
  }
wordt:
pid_t pid;
int   status;
if ((pid = fork()) < 0) {
  perror("fork");
  return (-1);
}
if (pid == 0) {
  /* kindproces */
  execl ("/bin/lpr", "lpr", "-Plisting", "stats.txt", NULL);
  perror ("execl");
  exit (-1);
}
/* moederproces */
waitpid (pid, & status, 0);
if ((! WIFEXITED (status)) || (WEXITSTATUS (status) != 0)) {
  perror ("Printing");
  return (-1);
}
   De code wordt duidelijk zwaarder! In sommige situaties wordt hij dan ook vrij
   complex, bijvoorbeeld wanneer je de standaard input van de applicatie opnieuw
   moet verwijzen, zoals in:
system ("mail root < stat.txt");
Dit betekent dat de verwijzing gedefinieerd door < wordt gedaan
vanuit de commandoregel. Je kan hetzelfde doen met een gecompliceerde sequence
zoals fork(), open(), dup2(),
execl(), etc. In dat geval zou het gebruik van de functie
system() een acceptabele oplossing zijn, maar dan moet wel de
hele omgeving veranderd worden.
In Linux worden de omgevingsvariabelen bewaard in de vorm van een pointer 
naar een tabel van karakters: char ** environ. Deze tabel eindigt 
met NULL. De strings hebben de vorm: "NAME=value".
We beginnen met het verwijderen van de omgeving met behulp van de GNU extensie:
    int clearenv (void);
of dwing de pointer
    extern char ** environ;
Om de Null waarde te kiezen. Nu worden de belangrijke omgevingsvariabelen
geïnitialiseerd, met behulp van gecontroleerde waardes, in de functies:
    int setenv (const char * name, const char * value, int remove)
    int putenv(const char *string)
Voor het aanroepen van de system() functie.
bijvoorbeeld :
    clearenv ();
    setenv ("PATH", "/bin:/usr/bin:/usr/local/bin", 1);
    setenv ("IFS", " \t\n", 1);
    system ("mail root < /tmp/msg.txt");
Als het nodig is, kan je de inhoud van enkele bruikbare variabelen
bewaren voordat je de omgeving verwijdert (HOME,
LANG, TERM, TZ,etc.). De
inhoud, de vorm en het formaat van deze variabelen moeten streng
worden gecontroleerd. Het is belangrijk dat je de hele omgeving moet verwijderen
voordat je de benodigde variabelen opnieuw gedefinieerd worden. Het
suidperl veiligheidsgat zou nooit zijn verschenen als de omgeving
correct was verwijderd.
Analoog hieraan betekent dit dat de bescherming van een machine op een netwerk inhoudt dat iedere connectie geweigerd dient te worden. Hierna activeert de systeembeheerder de benodigde en bruikbare services. Op dezelfde manier als bij het programmeren de omgeving opgeschoond moet worden en vervolgens gevuld moet worden met de benodigde variabelen bij een Set-UID applicatie.
Een parameter format wordt gecontroleerd door de verwachtte waarde te vergelijken met de toegestane formats. Als de vergelijking een match oplevert, wordt de parameter gevalideerd. Anders wordt hij afgewezen. Wanneer je de test draait terwijl je gebruik maakt van een lijst van ongeldige format waardes, wordt het risico van een verkeerde waarde verhoogd en dat kan een ramp betekenen voor het systeem.
We moeten begrijpen dat wat gevaarlijk is met system() ook 
gevaarlijk is voor daarvan afgeleide functies zoals popen(), of 
systeem-aanroepen zoals execlp() of execvp() als de
PATH variable in aanmerking wordt genomen.
Om de bruikbaarheid van een programma te verbeteren, is het makkelijk
   om de gebruiker de mogelijkheid te bieden om het grootste deel van de
   software te configureren, met behulp van macro's bijvoorbeeld. Om
   variabelen of "generic" patronen, te beheren zoals de commandoregel doet,
   bestaat er een krachtige functie genaamd wordexp(). Je moet
   er zeer voorzichtig mee zijn, aangezien een string als $
   (command) de uitvoer van het genoemde terminal commando
   toestaat. Het geven van de string "$(/bin/sh)" creëert een
   Set-UID commandoregel. Om dit te vermijden heeft wordexp()
   een attribuut genaamd WRDE_NOCMD die de interpretatie van
   de $( ) sequence deactiveert.
Als je een extern commando initieert moet je oppassen dat je geen
   programma aanroept dat de mogelijkheid biedt om te "ontsnappen" naar
   de commandoregel (zoals de vi :!commando sequence).
   Het is lastig om ze allemaal te noemen, van sommige applicaties is het
   duidelijk (tekst editors, bestandsmanagers...), maar anderen zijn lastiger
   te detecteren (zoals we hebben gezien met /bin/mail) of ze
   hebben gevaarlijke debug-modi.
Dit artikel illustreert verschillende aspecten:
Het volgende artikel zal gaan over gehuegen, de organisatie en de functie aanroepen voordat de buffer overflows bereikt worden. We zullen ook gaan zien hoe shellcode gebouwd moet worden.