[heap2.c]
heap2는 heap overflow, use after free를 이용한 문제인것 같다.
코드상에 auth chunk의 데이터가 들어가는 주소를 출력해주는 부분이 있는데,
이를 이용해서 쉽게 "you have logged in already!"라는 문구를 띄울 수 있다.
처음 "auth "를 입력하면 auth구조체의 크기 만큼 malloc을 해주는데
이 위치가 0x804c008이다.
이후 service를 입력하면 0x804c018의 위치에 메모리를 할당 받고, string을 복사해주는데,
이는 strdup()의 특성이다.
strdup()는 malloc() + strcpy()인데,
malloc()을 호출하여 string의 사본에 대한 기억장치 공간을 예약한다.
예를 들어 strdup("hello")를 하게 될 경우
h e l l o => 5 + 1을 하여 malloc(6)을 하고 이렇게 할당된 chunk에 hello라는 문자열을 복사해준다.
아무튼 두 chunk간의 offset이 0x10 == 16인데
이는 malloc(sizeof(auth))가 구조체의 크기만큼 heap을 할당하는게 아니라
구조체 포인터 변수만큼의 크기를 할당받기 때문이다.
일부러 헷갈리도록 구조체 이름과 포인터 변수 이름을 동일하게 해놓은 것 같다.
따라서 chunk auth는 header(8byte) + mem(8byte) = 총 16byte의 크기를 갖는다.
아무튼 이렇게 두 chunk간의 offset이 짧기 때문에 "service" + "16byte이상의 문자열"을 넣어주면
"you have logged in already!"라는 문자열을 띄울 수 있다.
위 그림처럼 ㅎ
하지만 나는 이게 이 문제의 진짜 의도라고 생각을 하지 않는다.
처음 이 문제의 메뉴를 봤을 때 생각난 취약점은 use-after-free 버그가 생각났다.
# use
if(strncmp(line, "auth ", 5) == 0) {
auth = malloc(sizeof(auth));
memset(auth, 0, sizeof(auth));
if(strlen(line + 5) < 31) {
strcpy(auth->name, line + 5);
}
}
# free
if(strncmp(line, "reset", 5) == 0) {
free(auth);
}
# reuse
if(strncmp(line, "service", 6) == 0) {
service = strdup(line + 7);
}
use-after-free bug에 대해 공부한적이 있는데
간단하게 어떤 버그인지만 알고 있다.
일정 크기의 chunk를 할당 받고, free를 한 후 다시 똑같은 크기의 chunk를 할당하고자 할때
이전 free했던 chunk를 재사용하기 때문에 생기는 버그라고 알고 있고,
이를 이용하면 이 문제의 풀이가 가능하다.
시나리오는 다음과 같다.
1. "auth " + "A"*30하여 총 36byte의 chunk를 할당받는다. // use
2. "reset" 하여 할당했던 메모리를 free해준다. // after free
3. "service" 하여 freed chunk를 재할당 받는다. // reuse
4. "service" + "C"*20하여 총 20byte를 할당받으면서 해당 chunk에 값복사를 진행한다. // auth->auth != 0
4. "login" 하여 인증한다.
gdb로 디버깅을 하면서 해당 시나리오대로 진행을 해보았다.
처음 바이너리를 실행 시키고, "auth "로 메모리 할당을 받았다.
이후 heap을 살펴보면 0x10만큼의 크기를 갖은 chunk가 할당된 것을 확인할 수 있다.
"reset"으로 free해주면 A가 들어가있던 자리에 0으로 초기화된다.
이후 "service BBB"하여 같은 크기의 chunk를 할당 받으면
이전에 free했던 chunk의 주소와 같은 곳을 가리키는 것을 확인할 수 있다.
다음으로 "service"+"C"*20하여 새로운 chunk를 할당 받음과 동시에 해당 chunk의 데이터 부분에 "C"로 도배해준다.
이후 auth->auth가 아주 큰 수로 초기화 된것을 확인 할 수 있다.
이상 풀이를 마친다.