System Hacking/Buffer Overflow

[Buffer Overflow] Return Address Overwrite 실습 - (1)

jir4vvit 2020. 8. 31. 15:18

참고 : dreamhack.io
환경 : ubuntu 16.04.7

 

 

Buffer Overflow란 프로그래머가 할당한 크기의 버퍼보다 더 큰 데이터를 입력받아 메모리의 다른 영역을 오염시키는 것이다.

 

이를 악용한다면 어딘가에 기계어 코드를 삽입한 후 Return Address의 함수 포인터를 공격자의 코드의 주소로 덮어 코드를 실행하는 것을 생각해볼 수 있다.

 

 

이 포스팅에서는 이것을 실습해보도록 하겠다. 

 

 


 

버퍼 오버플로우를 실습할 example.c 이다.

main 함수에서 프로그램의 argv[1]을 vuln 함수의 인자로 전달하는 것을 확인할 수 있다.

vuln 함수에서는 함수의 인자인 src 버퍼를 buf 버퍼에 strcpy 함수를 이용해 복사한다.

 

여기서 버퍼 오버플로우 취약점이 발견된다.

 

strcpy 함수는 두 번째 인자인 src 버퍼에 대한 길이 검증을 하지 않는다. 따라서 첫 번째 인자인 buf 배열이 크기보다 긴 문자열을 넣으면 스택 버퍼 오버플로우가 발생한다.

 

 

이때의 vuln 함수의 메모리 구조는 아래와 같다.

vuln 함수

vuln 함수의 인자인 src 문자열 포인터가 스택에 먼저 쌓이고, 그다음 Return address, Stack Frame Pointer가 순서대로 쌓인다.  그리고 제일 낮은주소에 지역 변수의 공간이 할당된다.

 

참고로 여기에 Stack Frame Pointer란 함수의 프롤로그에서 ebp 레지스터를 뜻한다.

 


본격적으로 디버깅을 해보자.

 

vuln 함수의 주소로 가 볼 것이다.

 

위와 같이 break point를 설정해 주었다.

 

 

그리고 argv[1] 인자로 "aaaabbbbccccddddeeeeffffgggghhhh"를 넣어주었다.

 

 

STACK에서도 확인할 수 있지만 명령어로도 확인할 수 있다.

esp 레지스터의 메모리를 word 타입으로 2개만큼(x/2wx) 출력해보았다.

첫번째는 명령어, 두번째는 스트링으로 출력하였다.

 

브레이크 포인트 에서의 스택 메모리를 보면, 첫 4바이트는 vuln 함수의 리턴 주소이고 다음 4바이는 vuln 함수의 인자인 argv[1]의 주소임을 알 수 있다.

 

 


이제 strcpy 함수가 실행되기 직전에 브레이크 포인트를 설정해 인자들을 확인해보자.

 

브레이크 포인트를 설정한 후 프로세스가 멈추어 있는 상태에서 continue(c) 명령을 통해 프로세스를 이어서 실행시켜주고

 

ni 명령을 통해 strcpy 함수를 실행시켜보자.

 

$esp의 첫 4바이트에 내가 입력한 문자열이 잘 복사되었는 것을 확인할 수 있다.

 

 

 

 

SFP랑 RET도 확인해보자.

 

SFP는 스택 주소값을 계산할 때 현재 스택값의 바닥, 즉 기준을 잡을 때 필요한 프레임 포인터 값을 저장하는 곳이다. 즉 이전함수의 EBP를 저장하고 있다. 크기는 4byte이다.

 

RET는 다음에 실행해야하는 명령이 위치한 메모리 주소이다.

빨간색 밑줄이 내가 입력한 문자열이 buf 변수, 즉 메모리 주소 0xffffd00c에 저장된 것이고,

노란색 박스가 SFP, 파란색 박스가 RET이다.

 

 

strcpy함수는 길이 검증을 하지 않기때문에 4바이트(SFP)를 포함해서 8바이트를 더 적어준다면 리턴 어드레스를 덮어쓸 수 있을 것이다.

 

 

 

 

 

 

그럼 buf에 내가 원하는 행동(쉘 획득)을 실행시키는 쉘코드를 작성하고 리턴어드레스를 buf가 시작되는 주소로 설정하면 내가 원하는 행동(쉘 따기)를 수행할 수 있지 않을까??

 

다음 (2)편에서 계속....