Integer Overflow

Υποστηρίξτε το HackTricks

Βασικές Πληροφορίες

Στην καρδιά μιας υπερχείλισης ακεραίων βρίσκεται ο περιορισμός που επιβάλλεται από το μέγεθος των τύπων δεδομένων στην προγραμματισμό υπολογιστών και την ερμηνεία των δεδομένων.

Για παράδειγμα, ένας 8-μπιτος ακέραιος χωρίς πρόσημο μπορεί να αναπαριστά τιμές από 0 έως 255. Εάν προσπαθήσετε να αποθηκεύσετε την τιμή 256 σε έναν 8-μπιτο ακέραιο χωρίς πρόσημο, θα επιστρέψει στο 0 λόγω του περιορισμού της χωρητικότητάς του. Αντίστοιχα, για έναν 16-μπιτο ακέραιο χωρίς πρόσημο, ο οποίος μπορεί να κρατήσει τιμές από 0 έως 65.535, η προσθήκη 1 στο 65.535 θα επιστρέψει την τιμή πίσω στο 0.

Επιπλέον, ένας 8-μπιτος ακέραιος με πρόσημο μπορεί να αναπαριστά τιμές από -128 έως 127. Αυτό συμβαίνει επειδή ένα bit χρησιμοποιείται για να αναπαραστήσει το πρόσημο (θετικό ή αρνητικό), αφήνοντας 7 bits για να αναπαραστήσουν το μέγεθος. Ο πιο αρνητικός αριθμός αναπαρίσταται ως -128 (δυαδικό 10000000), και ο πιο θετικός αριθμός είναι το 127 (δυαδικό 01111111).

Μέγιστες τιμές

Για πιθανές ευπάθειες στον ιστό είναι πολύ ενδιαφέρον να γνωρίζουμε τις μέγιστες υποστηριζόμενες τιμές:

fn main() {

let mut quantity = 2147483647;

let (mul_result, _) = i32::overflowing_mul(32767, quantity);
let (add_result, _) = i32::overflowing_add(1, quantity);

println!("{}", mul_result);
println!("{}", add_result);
}

Η αναπαράσταση ακέραιων αριθμών σε υπολογιστές είναι περιορισμένη από τον αριθμό των bits που χρησιμοποιούνται. Αυτό μπορεί να οδηγήσει σε προβλήματα υπερχείλισης ακεραίων όταν η τιμή ενός ακεραίου υπερβαίνει το μέγιστο δυνατό εύρος τιμών που μπορεί να αναπαραστήσει ο τύπος δεδομένων. Αυτό μπορεί να οδηγήσει σε μη αναμενόμενη συμπεριφορά του προγράμματος ή ακόμη και σε εκμετάλλευση από κακόβουλο κώδικα. Είναι σημαντικό να ελέγχετε την είσοδο και τις υπολογισμένες τιμές για να αποφευχθούν τέτοιου είδους ευπάθειες.

```c #include #include

int main() { int a = INT_MAX; int b = 0; int c = 0;

b = a * 100; c = a + 1;

printf("%d\n", INT_MAX); printf("%d\n", b); printf("%d\n", c); return 0; }

## Παραδείγματα

### Καθαρή υπερχείλιση

Το εκτυπωμένο αποτέλεσμα θα είναι 0 καθώς υπερχειλίσαμε το χαρακτήρα:
```c
#include <stdio.h>

int main() {
unsigned char max = 255; // 8-bit unsigned integer
unsigned char result = max + 1;
printf("Result: %d\n", result); // Expected to overflow
return 0;
}

Μετατροπή από Υπογεγραμμένο σε Ανυπογεγραμμένο

Λάβετε υπόψη μια κατάσταση όπου ένα υπογεγραμμένο ακέραιο διαβάζεται από την είσοδο του χρήστη και στη συνέχεια χρησιμοποιείται σε ένα πλαίσιο που το αντιμετωπίζει ως ανυπογεγραμμένο ακέραιο, χωρίς κατάλληλο έλεγχο:

#include <stdio.h>

int main() {
int userInput; // Signed integer
printf("Enter a number: ");
scanf("%d", &userInput);

// Treating the signed input as unsigned without validation
unsigned int processedInput = (unsigned int)userInput;

// A condition that might not work as intended if userInput is negative
if (processedInput > 1000) {
printf("Processed Input is large: %u\n", processedInput);
} else {
printf("Processed Input is within range: %u\n", processedInput);
}

return 0;
}

Άλλα Παραδείγματα

  • Χρησιμοποιείται μόνο 1B για να αποθηκεύσει το μέγεθος του κωδικού πρόσβασης, οπότε είναι δυνατόν να υπερχειλίσετε το μέγεθος και να το κάνετε να νομίζει ότι έχει μήκος 4 ενώ στην πραγματικότητα είναι 260 για να παρακάμψετε τον έλεγχο μήκους προστασίας

  • Δεδομένων δύο αριθμών, βρείτε χρησιμοποιώντας το z3 ένα νέο αριθμό που πολλαπλασιασμένος με τον πρώτο θα δώσει τον δεύτερο:

(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
  • Χρησιμοποιείται μόνο 1B για να αποθηκεύσει το μέγεθος του κωδικού πρόσβασης, οπότε είναι δυνατόν να υπερχειλίσετε το μέγεθος και να το κάνετε να νομίζει ότι έχει μήκος 4 ενώ στην πραγματικότητα είναι 260 για να παρακάμψετε τον έλεγχο μήκους προστασίας και να αντικαταστήσετε στη στοίβα την επόμενη τοπική μεταβλητή και να παρακάμψετε και τις δύο προστασίες

ARM64

Αυτό δεν αλλάζει στο ARM64 όπως μπορείτε να δείτε σε αυτή την ανάρτηση στο blog.

Last updated