2015-05-20 20 views
6

Ben yığın taşması saldırıları hakkında öğreniyorum ve benim ders kitabı aşağıdaki savunmasız C kodu sağlar:Öbek Taşma Saldırı

/* record type to allocate on heap */ 
typedef struct chunk { 
    char inp[64];   /* vulnerable input buffer */ 
    void (*process)(char *); /* pointer to function to process inp */ 
} chunk_t; 

void showlen(char *buf) 
{ 
    int len; 
    len = strlen(buf); 
    printf("buffer5 read %d chars\n", len); 
} 

int main(int argc, char *argv[]) 
{ 
    chunk_t *next; 

    setbuf(stdin, NULL); 
    next = malloc(sizeof(chunk_t)); 
    next->process = showlen; 
    printf("Enter value: "); 
    gets(next->inp); 
    next->process(next->inp); 
    printf("buffer5 done\n"); 
} 

Ancak ders kitabı kimse bu güvenlik açığını düzeltmek nasıl açıklamıyor. Birisi güvenlik açığı ve bunu düzeltmek için bir yol (lar) açıklayabilirdi, bu harika olurdu. (Sorunun bir kısmı Java'dan geliyorum, değil C)

+4

'inp'niz 64 bayttır. 65 bayt giriş yapın ve taştığınız için ... –

+4

Ve düzeltmek için, [fgets() kullanın] (http://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous -tüm-kullanılmaması gereken) –

+0

@orangesoda bu kitap hangisi? –

cevap

5

sorun gets() bir yeni satır okur veya EOF ulaşıncaya kadar tampon belleğe okumaya devam edecektir kullanmak -

sadece 63 byte (null bir) diziye inp içine okunur sağlamak basit düzeltmek için. Tamponun boyutunu bilmiyor, bu yüzden sınırına ulaştığında durması gerektiğini bilmiyor. Çizgi 64 bayt veya daha uzunsa, bu arabelleğin dışına gider ve process'un üzerine yazacaktır. Eğer girdiyi giren kullanıcı bunu bilirse, program işaretçisini yerine program çağrısı yapmak istediği başka bir işleve bir işaretçi ile değiştirmek için pozisyon 64'te sadece doğru karakterleri yazabilir.

Düzeltme, gets() dışında bir işlev kullanmaktır, böylece okunacak giriş miktarında bir sınır belirtebilirsiniz. Bunun yerine

gets(next->inp); 

size kullanabilirsiniz:

fgets(next->inp, sizeof(next->inp), stdin); 

fgets() ikinci argüman o next->inp içine en fazla 64 bayt yazmak için söyler. Bu yüzden stdin'dan en fazla 63 bayt okuyacaktır (boş dizge sonlandırıcısı için bir bayta izin vermesi gerekir).

5

Bu kod, olası güvenlik sorunuyla meşhur olan gets'u kullanır: Bu sürücüye geçirdiğiniz arabellek uzunluğunu belirtmenin bir yolu yoktur. 'dan \n veya EOF ile karşılaşana kadar okumaya devam edeceğim. Bu nedenle, arabellek taşması ve bunun dışında belleğe yazabilir ve sonra kötü şeyler olacak - çökebilir, koşmaya devam edebilir, porno oynamaya başlayabilir.

Bunu düzeltmek için, bunun yerine fgets kullanmalısınız.

1

Adresinizi process olarak ayarlayarak, 64 bayttan daha fazlasıyla doldurabilirsiniz. Böylece biri istediği her şeyi girebilir. Adres herhangi bir işlevin bir göstergesi olabilir. fgets

0

İşlev, stdin'dan gelen metin miktarını sınırlamaz. Eğer 63'ten fazla karakter stdin'dan geliyorsa, bir taşma olacaktır. Allar, [Enter] tuşu olan LF karakterini atar, ancak sonunda bir null char ekler, böylece 63 karakter sınırı vardır. strlen boyutunu belirlemek için inp ötesinde boş-Char arayacaktır gibi doğrudan ulaşılabilir olarak inp de değer, 64 boş olmayan karakter ile doluysa

, showlen fonksiyon, bir erişim ihlali tetikleyecektir.

fgets'u kullanmak ilk sorun için iyi bir çözüm olabilir, ancak bir LF karakterini ve null'ı da ekler, böylece okunabilir metnin yeni sınırı 62 olur.an için

, sadece inp üzerine yazılanları ilgileneceğim.