hacktricks/binary-exploitation/integer-overflow.md

5.6 KiB

정수 오버플로우

{% hint style="success" %} AWS 해킹 학습 및 실습:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 학습 및 실습: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks 지원
{% endhint %}

기본 정보

정수 오버플로우의 핵심은 컴퓨터 프로그래밍에서 데이터 유형의 크기와 데이터의 해석에 의해 부과된 제한입니다.

예를 들어, 8비트 부호 없는 정수0부터 255까지의 값을 나타낼 수 있습니다. 8비트 부호 없는 정수에 256 값을 저장하려고 하면 저장 용량의 제한으로 인해 0으로 감싸집니다. 마찬가지로, 16비트 부호 없는 정수0부터 65,535까지의 값을 보유할 수 있으며, 65,535에 1을 더하면 값이 다시 0으로 돌아갑니다.

또한, 8비트 부호 있는 정수-128부터 127까지의 값을 나타낼 수 있습니다. 이는 하나의 비트가 부호(양수 또는 음수)를 나타내는 데 사용되어 크기를 나타내는 데 7비트가 남기 때문입니다. 가장 음수인 숫자는 -128 (이진 10000000으로 표시)이고, 가장 양수인 숫자는 127 (이진 01111111로 표시)입니다.

최대 값

잠재적인 웹 취약점을 위해 지원되는 최대 값을 알아두는 것이 매우 흥미로울 수 있습니다:

{% tabs %} {% tab title="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 title="C" %} 정수 오버플로우는 산술 연산에서 발생할 수 있는 일반적인 보안 취약점 중 하나입니다. 이러한 취약점은 변수가 특정 범위를 초과하여 최대값으로 다시 돌아가거나 음수가 될 때 발생합니다. 이러한 상황은 프로그램이 예상치 못한 방식으로 동작하게 하여 공격자가 코드 실행 흐름을 조작할 수 있게 합니다. {% endtab %}

#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;
}

예시

순수 오버플로우

출력된 결과는 문자를 오버플로우했기 때문에 0이 될 것입니다:

#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;
}

다른 예시

(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)

ARM64

ARM64에서도 변경되지 않습니다. 이 블로그 게시물에서 확인할 수 있습니다.