* 9 *

Softwaresikkerhet I

Selv-test spørsmål

  1. Beskriv de viktigste ting man må tenke på når man lager sikker software.
  2. Forklar hvorfor følgende systemkallet som leser input fra en bruker nødvendigvis er farlig.
    char buffer[1024];
    
    gets(buffer);
    
    Hint: hvilken informasjon mangler gets()?

Karaktergivende oppgaver

Hensikten med de praktiske oppgavene denne uken er å lære om "buffer overflows". Dette er et problem som oppstår svært ofte i uforsiktig skrevet software. Vi kommer til å diskutere dette i de kommende ukene. Kompiler følgende programmet, først på Solaris og så på GNU/Linux og sjekk om resultatet er avhengig av operativsystem.
/*****************************************************************************/
/*                                                                           */
/* File: overflow1.c                                                         */
/*                                                                           */
/*****************************************************************************/

#include 

main()

{ char buffer[8];

printf("Please enter your name:"); 
scanf("%s",buffer);

printf("Your name is: [%s]\n",buffer);

Function1();
Function2(); 
}

/*****************************************************************************/

Function1()

{ char buffer[100];

sprintf (buffer,"Mary had a little lamb whose fleece was white as /bin/sh BadScript ...");
printf("%.22s\n",buffer); 
}

/*****************************************************************************/

Function2()

{ char buffer[50];
 
printf("Execute command %s\n",buffer);
}


  1. Se på bufferstørrelsen til char arrayene i de ulike funksjonene.
  2. Prøv å taste inn en veldig lang linje ved ledeteksten i programmet. Programmets utskrift ser omtrent slik ut:
    Please enter your name:abcdef
    Your name is: [abcdef]
    Mary had a little lamb
    Execute command  /bin/sh BadScript ...    
    
    Kan du forklare dette?
  3. Anta at dette hadde vært et program som ble kjørt som root og at Function2 hadde ikke bare skrevet til skjermen, men faktisk hadde eksekvert strengen den nå skriver på skjermen. Hva ville skjedd? Anta også at Function1 hentet en streng fra brukeren i steden for at den brukte en statisk streng. Hvor ligger faren her? Hvordan kunne man unngått problemet?
Prov nå følgende programmet:
/*****************************************************************************/
/*                                                                           */
/* File: overflow2.c                                                         */
/*                                                                           */
/*****************************************************************************/

#include 

main()

{
Function1();
Function2(); 
}

/*****************************************************************************/

Function1()

{ char buffer[100];

scanf("%[^\n]",buffer);
}

/*****************************************************************************/

Function2()

{ char buffer[50];

printf("01234567890123456789001234567890012345678901234567890\n"); 
printf("Executing command %s\n",buffer); 
system (buffer);
}

Et av de største hodepiner for programmerere som skriver interaktive programmer (inkludert klient-server systemer) er streams. Du har sikkert hørt om streamsbiblioteket for C++, men du må ikke tro at det er noe som ku gjelder for C++ eller sine biblioteker.

En stream eller datastrøm er en kontinuerlig foring av input/output som innholder flere data objekter. Lengden på datastrømmen er ukjent i utgangspunktet, men strømmen er terminert ved en EOF (end of file) markør. Overførsel av data ved hjelp av datastrømmer kan kontrastes med overførsel av datablokker av kjent antall og størrelse.

De bestkjente datastrømmene heter standard-in/stdin og standard-out/stdout. Det er vanligvis keyboard input og konsoll output. Hver gang vi ber en bruker om å skrive noe, åpner vi en kanal til tastaturstrømmen. Inputen avsluttes når brukeren taster ENTER.

Hensikten med denne ukens oppgaver er å kaste lys på noen av problemene omkring stream-programmering. Hvorfor er det vanskelig? Hvorfor er det en av de vanligste feilkildene i interaktivprogrammering. Vi kommer til å kode i både C og C++.

  1. De komplemntære funksjonene for å lese data i C og C++ er henholdsvis
    
          C                        C++
    
       int a;                   int a;
    
       scanf("%d",&a);          cin >> a;
    
    Disse er blant de vanskeligste og farligste funksjoner å beherske, av to grunner: Prøv å kompilere de følgende programmene i C/C++.
    
     #include <stdio.h>                               #include <iostream>
    
     main()                                               main()
    
     { int a = 0;                                         { int a = 0;
       static char buffer[20] = "rm *";                     static char buffer[20] = "rm *"; 
    
     printf ("Enter [uid] [command]: ");                   cout << "Enter [uid] [command]: ";
    
     scanf("%d %s",&a,buffer);                             cin >> a >> buffer;
    
     printf("Okay, executing %s as user %d\n",buffer,a);   cout << "Okay, executing " << buffer << " as user " << a << endl;
     }                                                     }
    
    
    Prøv å skrive inn følgende som input til programmet:
    100 ls
    100ls
    ls 100
    
    Kan du forklare resultatene? Anta at dette programmet var en server på en Unix maskin. Hva kunne skjedd i det siste tilfelle?

  2. Anta at vi skal skrive en sikker protokoll for å overføre ordre fra regjerningen til en kjerneubåt. La oss simulere kommunikasjonskanalen ved å bruke stdin. Det samme oppførsel gjelder også data via nett/sockets som vi kommer til å se i den neste forelesningen. Her ser vi på inkorrekt tolking av input og denial of service angrep. Tast inn dette C++ programmet:
    #include <iostream>
    
    main()
    
    { char command[40];   // Send command to 
      int time_of_day;    // Avoid replay attack?
    
    cin >> time_of_day >> command;
    cout << "Command was " << command << " at time " << time_of_day << endl;
    }
    
    og prøv programmet med følgende input:
    13 report
    13 shoot-to-kill
    15 shoot only if they shoot first
    12:00 fire
    

    Anta nå at vi lager en løkke rundt dette for å hente ny ordrer, som i en server som lytter kontinuerlig:

    #include <iostream>
    
    main()
    
    { char command[40];   // Send command to 
      int time_of_day;    // Avoid replay attack?
      const bool ever = 1;
      
    for ( ;ever; )
       {
       cin >> time_of_day >> command;
       cout << "Command was " << command << " at time " << time_of_day << endl;
       }
    }
    
    
    Prøv å taste inn den samme input som før. Ser du hvor lett det er å utføre en denial of service angrep? Den samme feilen fantes i NT-4, før Service Pack 2. Problemet er vanskelig å fikse med C++ streams-biblioteket, men det er lett å fikse med C's I/O bibliotek.
    #include <stdio.h>
    
    #define ever 1
    
    main()
    
    { char command[40];   // Send command to 
      int time_of_day;    // Avoid replay attack?
      
    for ( ;ever; )
       {
       scanf("%d %[^\n]",&time_of_day,command);
       printf("Command %s at time %d\n",command,time_of_day);
       }
    }
    
    
    Regulærutrykket %[^\n] matcher et objekt som består av en hvilken som helst sammensetning av tegn bortsett fra `end of line'. Dvs, dette matcher alt fram til slutten av linjen.
Documenter dette arbeidet til den neste obligatoriske innlevering.

Back