4.3 KiB
Tam Sayı Taşması
{{#include ../banners/hacktricks-training.md}}
Temel Bilgiler
Bir tam sayı taşmasının merkezinde, bilgisayar programlamasındaki veri türlerinin boyutu ve verinin yorumlanması tarafından dayatılan sınırlama bulunmaktadır.
Örneğin, bir 8-bit işaretsiz tam sayı 0 ile 255 arasındaki değerleri temsil edebilir. Eğer 256 değerini bir 8-bit işaretsiz tam sayıya depolamaya çalışırsanız, depolama kapasitesinin sınırlılığı nedeniyle değer 0'a döner. Benzer şekilde, 0 ile 65,535 arasındaki değerleri tutabilen bir 16-bit işaretsiz tam sayı için, 65,535'e 1 eklemek değeri tekrar 0'a döndürür.
Ayrıca, bir 8-bit işaretli tam sayı -128 ile 127 arasındaki değerleri temsil edebilir. Bunun nedeni, bir bitin işareti (pozitif veya negatif) temsil etmek için kullanılmasıdır; bu da geriye 7 bitin büyüklüğü temsil etmesi için kalması demektir. En negatif sayı -128 (ikili 10000000
) olarak, en pozitif sayı ise 127 (ikili 01111111
) olarak temsil edilir.
Maksimum değerler
Potansiyel web güvenlik açıkları için maksimum desteklenen değerleri bilmek oldukça ilginçtir:
{{#tabs}} {{#tab name="Rust"}}
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);
}
{{#endtab}}
{{#tab name="C"}}
#include <stdio.h>
#include <limits.h>
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;
}
{{#endtab}} {{#endtabs}}
Örnekler
Saf taşma
Yazdırılan sonuç 0 olacak çünkü char'ı taşırdık:
#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;
}
Signed to Unsigned Conversion
Kullanıcı girdisinden okunan bir işaretli tam sayının, uygun bir doğrulama olmaksızın, işaretsiz bir tam sayı olarak ele alındığı bir durumu düşünün:
#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;
}
Bu örnekte, bir kullanıcı negatif bir sayı girerse, bu sayı ikili değerlerin yorumlanma şekli nedeniyle büyük bir işaretsiz tam sayı olarak yorumlanacak ve beklenmedik davranışlara yol açabilir.
Diğer Örnekler
-
https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html
-
Parolanın boyutunu saklamak için yalnızca 1B kullanıldığı için, bunu taşırmak ve uzunluğunun 4 olduğunu düşünmesini sağlamak mümkündür, oysa aslında 260'dır ve uzunluk kontrol korumasını atlatır.
-
https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html
-
Birkaç sayı verildiğinde, z3 kullanarak ilk sayı ile çarpıldığında ikinci sayıyı veren yeni bir sayı bulun:
(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
- https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/
- Parolanın boyutunu saklamak için yalnızca 1B kullanıldığı için, bunu taşırmak ve uzunluğunun 4 olduğunu düşünmesini sağlamak mümkündür, oysa aslında 260'dır ve hem uzunluk kontrol korumasını atlatır hem de yığında bir sonraki yerel değişkeni üzerine yazar.
ARM64
Bu ARM64'te değişmez; bu blog yazısında görebileceğiniz gibi.
{{#include ../banners/hacktricks-training.md}}