본문 바로가기

Security/Pwnable

Dreamhack-Memory Corruption - C(1)

 

본 포스팅은 Dreamhack사이트의 Memory Corruption - C(1)를 제가 공부 하기 좋게 요약 한 것 입니다.

 

OOB(Out of Boundary) : 버퍼의 길이 범위를 벗어나는 인덱스에 접근할 때 발생하는 취약점.

이는 올바르지 않은 값이 버퍼의 인덱스로 사용될 경우 발생한다.

 

int형 변수 idx를 입력받은 후 이 값을 크기가 10인 int형 배열 buf의 인덱스 값으로 넣어 출력한다.

 

위 문제에서 buf의 크기가 10이므로 buf는 0 <= x < 10 의 정수이다. 

****여기서 idx를 사용자로 부터 입력을 받는데 이의 크기를 검사하는 코드가 존재하지 않음. 따라서 이를 이용해 buf영역 밖에 접근 할 수 있다.

위와 같이 index값에 11을 넣고 문제를 풀면 된다.


oob-2.c

oob-1.c에서 12번째 줄 idx = idx % 10이 추가된 코드이다. 

12번째 줄의 코드를 추가하면서 사용자로부터 입력 받는 idx값을 검사한다.

 

****양의 정수를 10으로 나누면 나타날 수 있는 값은 0~9이기 때문에 이는 얼핏 보면 안전해 보이지만 음의 정수를 입력할 경우 인덱스 값이 음수로 나와 총 -9 ~ 9의 값이 나올 수 있어 이를 이용해 OOB를 발생시킬 수 있다.

 


oob-3.c

위의 코드에서 13~15번째 줄 코드가 추가됬다.

이 코드 때문에 음수 값을 입력 해도 OOB를 발생시킬 수 없게 되었다.

 

****이 문제를 해결하기 위해서는 int형이 32비트인 것을 이용해야 한다. int형에서 표현 가능한 정수의 범위는

-pow(2, 31) ~ pow(2, 31) -1 까지이다. 그래서 int형에서는 -pow(2, 31)는 표현이 가능하지만 pow(2, 31)

는 표현이 불가능하고 pow(2, 31)는 표현 가능한 정수보다 하나 큰 -pow(2, 31)로 바뀌게 된다.

 

이 문제를 근본적으로 막기 위해서는 idx라는 변수를 int 형이 아닌 unsigned int로 선언하거나, 인덱스를 입력받은 후에 if( idx < 0 || idx >= 10)과 같은 경계 검사 구문을 추가하면 된다.

-pow(2, 31)을 입력해 13~15번째 코드에 의해 pow(2, 31)로 바뀌게 되고 int형의 정수 표현 한계 때문에 결국 

-pow(2, 31)이 된다.

-pow(2, 31) = -2147483648

 


Off-by-one 취약점은 경계 검사에서 하나의 오차가 있을 때 발생하는 취약점입니다. 이는 버퍼의 경계 계산 혹은 반목문의 횟수 계산 시 <대신 <=을 쓰거나, 0부터 시작하는 인덱스를 고려하지 못할 때 발생한다.

 

 

off-by-one-1.c

copy_buf함수 내부에서 반복문을 0~sz(16)까지 도는 것이 off-by-one 오류를 발생시키는 원인이다.

이를 해결하기 위해서 for(i=0; i < sz; i++)와 같이 인덱스를 생각해서 코딩을 해주면 된다.

위와같이 A를 입력하며 overflow가 일어나는 것을 확인할 수 있다.