2017/01/11 - [Study :)/FTZ] - [해커스쿨] FTZ level8 풀이과정
힌트를 봐야 겠지?
힌트를 보니 Buffer Overflow 문제인 것같다.
버퍼 오버플로우는 어떻게 발생하는가?
버퍼 오버플로우를 이해하기 위해서는 먼저 프로그램이 데이터를 어떻게 저장하고 어떻게 함수가 호출되는지 알아야 한다. 하나의 프로그램은 수 많은 함수로 구성되어 있는데 이 함수가 호출될 때, 지역 변수와 복귀 주소(Return Address)가 스택(Stack)이라 하는 논리 데이터 구조에 저장된다. 복귀 주소가 저장되는 이유는 함수가 종료될 때 운영체제가 함수를 호출한 프로그램에 제어권을 넘겨야 하는데, 이 복귀주소가 없으면 함수가 종료된 후 어떤 명령어를 수행해야 할 지 모르기 때문이다.
버퍼 오버플로우는 이 복귀 주소가 함수가 사용하는 지역 변수의 데이터에 의해 침범 당할 때 발생한다. 프로그래머 실수로 지역 변수가 할당된 크기보다 더 많은 데이터를 입력하면(위 그림 b) 복귀 주소가 이 데이터에 의해서 다른 값으로 변경이 되기 때문에 함수가 종료될 때 엉뚱한 복귀 주소를 실행시키게 되어서 어플리케이션이 뜻하지 않게 종료됩니다. 더 문제는 악의적인 공격자가 이 버퍼 오버플로우 결함을 이용하는 경우이다. 보통 버퍼 오버플로우 공격(Buffer Overflow Attack)이라고 하는데, 공격자가 이 취약점을 알고 데이터의 길이와 내용을 적절히 조정해서 버퍼 오버플로우를 일으켜서 특정 코드를 실행시키게 하는 해킹 기법에 사용된다.
그러면 버퍼 오버플로우를 발생시키지 않으려면 어떠한 입력값을 받을때 입력값의 크기를 프로그래머가 지정해줘야 되는데,
위 힌트를 보면 buf, buf2의 배열의 크기는 각각 10byte이다. 그런데 입력받는 fgets함수는 40byte만큼 입력을 받는다.
그리고 나서 buf에 입력값을 저장하는데... 10byte보다 큰 데이터량을 입력시키면 어떻게 될까?
궁금함을 해결하기 위해서 예제 코드를 만들어 봤다.
level9와 비슷한 코드지만, buf에 10byte이상 데이터를 넣었을때 buf와 buf2에 어떤값들이 들어가는지 알아보기 위한 예제이다.
해당 프로그램을 실행하고 "A"10개, "B"10개를 입력했떠니... 저런 엉뚱한 값들이 나타난다.
두가지의 의문점이 나타난다..
첫번째, 분명 buf,와 buf2는 10byte의 배열로 정의했는데, buf의 표현된 값을 보니 20byte모두 표현됬다.
두번쨰, buf2에는 값을 넣는 함수가 어느 하나도 없는데, buf2의 값이 표현됬다.
여기서 유추해볼 수 있는 것은 buf배열을 우리가 10byte만큼 할달 하였지만, 메모리상에는 16byte만큼 할달 되었고,
buf2는 그다음 메모리주소부터 할당 되었을거다.
그리고 buf에 20byte만큼 입력값을 넣으면 16byte를 초과한 4byte는 buf2배열 메모리상에 오버플로우 됬구나... 라는 추측을 할 수 있다.
그러면 리버싱으로 확실하게 알아보자.
어떠한가? 추측한 것과 똑같지 않은가?
그러면 "AAAAAAAAAABBBBBBBBBB"값을 넣었을때 스택은 어떻게 되어있나도 한번 살펴보자.
<main+36>에 브레이크 포인트를 걸고 실행시켜 보겠다.
버퍼에도 똑같이 "A"가 10개 "B"가 10개씩 순차적으로 들어가 있다.
그럼 다시 문제로 돌아와서 힌트를 다시 보자.
힌트를 자세히 보면 buf에 입력값을 넣지만, if문속에는 buf2의 값을 비교한다.
즉, buf에 10byte이상의 값을 넣어서 buf2 스택 주소에 오버플로우 시켜서 buf2의 2byte에 "go"라는 문자열이 있으면 setreuid 함수가 실행되면서 level10의 권한을 얻게 되는 것이다.
앞서 계속 설명 했듯이, buf의 배열은 10byte를 할당 했지만, gcc때문인지 몰라도 16byte씩 할당 되는 것을 확인 했다.
그러면 buf2 첫 2byte에 go라는 명령어를 넣으려면 buf에 얼만큼의 데이터를 넣고 "go"라고 넣어야 되는지 감이 올 것이다.
"A"로 16byte만큼 채워주고 "go"라고 적어주면 buf2에 "go"라는 문자열이 오버플로우되어 들어간다.
level10의 password는 my-pass 명령어를 치면 나오겠지?