스택 오버플로우는 입력받는 버퍼의 길이를 검사하지 않아
연속적인 메모리 특성상 다른 값의 변조 위험이 생기는 것을 의미합니다.
특히 버퍼에 명령어를 입력한 후 Return Address를 명령어를 입력한
버퍼로 변조 한후 버퍼에 입력된 명령어를 실행시킬 수 있어
오버플로우 취약점은 굉장히 위협적일 수도 있습니다.
스택 프레임 포인터(SFP) 는 함수가 종료된 이후 다시 되돌아갈
스택 주소를 담고 있습니다.
그리고 리턴 어드레스 (return address) 는 함수 종료 이후 다시 되돌아갈
명령어의 주소를 담고 있습니다.
#include <stdio.h>
int main()
{
char buf[0x30];
scanf("%s", buf);
return 0;
}
다음과 같은 코드가 있을 때에 main() 의 스택 구조는 다음과 같습니다.
위와 같은 코드에서 buf 에 입력을 받을 때에 아무런 검증을 하지 않아
공격자는 buf의 길이를 넘는 입력을 하여 return address를 조작할 수 있습니다.
이처럼 공격자가 return address의 값을 변조하면 프로그램의 실행 흐름을
공격자 마음대로 바꿀 수 있게 됩니다.
우선 오버플로우 취약점이 발생할 수 있는 코드를 다음과 같이
작성하였습니다.
실습의 편의를 위해 메모리 보호기법(canary, PIE)를 적용시키지 않았습니다.
checkseck 명령어로 컴파일된 ELF 파일을 확인해보면 Canary와 PIE가 적용되어 있지
않다는 것을 확인할 수 있습니다.
이제 welcome_admin() 을 실행시키기 위해 welcome_admin() 의 주소를
확인해야 합니다. 현재 ELF 파일에 PIE가 적용되어 있지 않으므로 주소는 고정된 값입니다.
gdb로 welcome_admin 의 주소를 확인해 보면 0x0000000000400557인 것을
확인할 수 있습니다.
따라서 프로그램 그 어디에서도 호출하지 않는 welcome_admin() 을 실행시키기 위한
쉘 코드는 다음과 같습니다.
gcc를 통해 x86-64 로 컴파일을 하여 SFP의 크기는 8byte 입니다.
x86 환경의 경우 SFP의 크기는 4byte 입니다.
작성한 쉘 코드를 실행시키면 결과는 다음과 같이 나오게 됩니다.
위와 같이 프로그램에서 호출되지 않은 welcome_admin() 을 호출할 수 있습니다.