해킹 공부/시스템 해킹

DreamHack Stage 13_type Error

O'bin 2022. 8. 1. 14:39

변수 자료형 선언시 담을 값의 크기, 용도, 부호 여부 고려 필요

Type error 부적절한 자료형을 사용했을 때 발생

 

 

- Out of Range: 데이터 유실

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Name: out_of_range.c
// Compile: gcc -o out_of_range out_of_range.c
 
#include <stdio.h>
unsigned long long factorial(unsigned int n) {
  unsigned long long res = 1;
  for (int i = 1; i <= n; i++) {
    res *= i;
  }
  return res;
}
int main() {
  unsigned int n;
  unsigned int res;
  printf("Input integer n: ");
  scanf("%d"&n);
  if (n >= 50) {
    fprintf(stderr, "Input is too large");
    return -1;
  }
  res = factorial(n);
  printf("Factorial of N: %u\n", res);
}
cs

 

정수를 입력받아 팩토리얼 결과를 반환하는 코드이다.

입력값을 1씩 증가하면서 넣어보면,

17까지는 꾸준히 증가하던 결과가 18을 입력한 순간 급격히 작아지는 일이 발생한다.

 

18!=0x16beecca730000인데, 이 결과를 4바이트 크기의 res에 대입하려 하면,

상위 4byte는 버려지고, 하위 4byte인 만 남는다.

=> 변수에 어떤 값을 대입할 때, 그 값이 변수에 저장될 수 있는 범위를 벗어나면,

     저장할 수 있는 만큼만 저장하고 나머지는 모두 유실

 

 

 

- Out of Range: 부호 반전과 값의 왜곡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Name: oor_signflip.c
// Compile: gcc -o oor_signflip oor_signflip.c
#include <stdio.h>
unsigned long long factorial(unsigned int n) {
  unsigned long long res = 1;
  for (int i = 1; i <= n; i++) {
    res *= i;
  }
  return res;
}
int main() {
  int n;
  unsigned int res;
  printf("Input integer n: ");
  scanf("%d"&n);
  if (n >= 50) {
    fprintf(stderr, "Input is too large");
    return -1;
  }
  res = factorial(n);
  printf("Factorial of N: %u\n", res);
}
cs

 

main 함수에서 입력값 n 이 int형이 되었다 = 음수 입력 통해 16번째 줄의 검사 우회 가능

factorial함수는 unsigned int n을 인자로 받으므로, int n 이 음수로 입력되면 부호가 없어진 매우 큰 값의 양수가 factorial 함수에 들어가게 됨

 

=> 이런 문제예방하려면 양수로만 쓰일 값반드시 unsigned를 붙이는 습관 필요

 

 

 

 

- Out of Range와 버퍼 오버플로우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Name: oor_bof.c
// Compile: gcc -o oor_bof oor_bof.c -m32
#include <stdio.h>
#define BUF_SIZE 32
 
int main() {
  char buf[BUF_SIZE];
  int size; // int 형이므로 아래 검사 우회 가능
  
  printf("Input length: ");
  scanf("%d"&size);
  
  if (size > BUF_SIZE) { //버퍼오버플로우 방지 위해 size 값 검사
    fprintf(stderr, "Buffer Overflow Detected");
    return -1;
  }
  
  read(0, buf, size);
  return 0;
}
cs

size에 음수 넣으면 13번 줄 검사 우회 가능

size에 -1을 넣고 32byte보다 큰 데이터 넣으면 스택 버퍼오버플로우 발생

 

 

- 타입 오버플로우와 언더플로우

Type Overflow/Underflow : 변수의 값이 연산 중에 자료형의 범위를 벗어나면, 갑자기 크기가 작아지거나 커지는 현상

 

 

 

 

- Integer Overflow와 버퍼 오버플로우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Name: integer_overflow.c
// Compile: gcc -o integer_overflow integer_overflow.c -m32
 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
 
int main() {
  unsigned int size;
  scanf("%u"&size);
  
  char *buf = (char *)malloc(size + 1);
  unsigned int read_size = read(0, buf, size);
  
  buf[read_size] = 0;
  return 0;
}
cs

사용자가 size에 4294967295 (unsigned int의 최댓값) 입력시

size+1은 0 됨(intetger overflow 발생), malloc에 전달 되면 32byte(최소 할당 크기) 청크 할당

그러나 read 함수는 size 값 그대로 사용

=> 32byte 청크에 4294967295 만큼 값 쓸 수 잇음 -> 힙 버퍼오버플로우 발생

 

 

취약점이 될 수 있는 부분이기 때문에 개발 시 들어가는 값 고려해서 자료형 선언해야 함