LOB giant Write-Up
LOB giant 풀어보자.
주어진 코드를 보면 첫 번째 인자가 "\xbf" 또는 "\x40"으로 시작하면 프로그램을 종료시킨다. 아래에서 확인하겠지만 첫 번째 인자의 44~47번째 값들은 ret를 변조시키는데 ret를 buffer 변수, 환경변수, argv, 공유 라이브러리 주소로 변조할 수 없다는 뜻이다.
먼저 main 함수의 어셈블리어 코드를 보면 strcpy 함수를 호출하기 전에 ebp-0x28 주소를 eax 레지스터에 저장한다. 즉, 이 곳이 buffer 변수의 시작점이다.
따라서 스택은 위와 같이 형성될 것이고, buffer 변수부터 44bytes의 값을 입력하면 ebp까지 변조할 수 있다.
임의의 값 44bytes를 입력하고 4bytes를 입력하면 ret를 변조할 수 있지만 [사진 1]에서 확인했듯이 buffer 변수, 환경변수, argv 인자, 공유 라이브러리 주소를 입력할 수 없다. ret 명령어를 이용하여 풀어보자.
ret 명령어의 기능은 다음과 같다.
1) pop eip // 현재 esp가 가리키는 스택의 값을 eip 레지스터에 저장한다.
2) jmp eip // eip 레지스터에 저장된 값은 다음에 실행할 명령어이므로 해당 명령어로 점프한다.
즉, ret 값을 명령어 ret의 주소로 변조하면 ret 명령어가 수행되고 ebp+8 지점의 값이 eip 레지스터에 저장될 것이다.
따라서 buffer 변수에 shellcode를 저장하고 ebp+8 지점에 buffer 변수의 주소를 입력하면 된다.
먼저 명령어 ret의 주소를 찾아야 하는데 objdump 명령어로 쉽게 찾을 수 있다. [사진 5]에서 확인할 수 있는 모든 ret 명령어의 주소를 사용할 수 있다. 여기선 0x08048336 주소를 사용한다.
디버깅하기 위해 assassin 파일을 다른 이름(kssassin)으로 복사해준다. 입력 값으로 임의의 값 "\x90" 44bytes와 명령어 ret의 주소로 ret 지점까지 변조하고 ebp+8 지점은 문자열 "ABCD"를 넣었다.
위와 같이 buffer 변수의 시작 주소는 0xbffffac0이고 ebp까지 변조된 것을 확인할 수 있다. 그리고 ret는 명령어 ret의 주소로 변조되었고, ebp+8 지점인 0xbffffaf0 주소도 "ABCD" 문자열로 변조되었다.
따라서 nop "\x90" 19bytes와 shellcode 25bytes를 입력하여 ebp까지 변조하고 명령어 ret의 주소로 ret 지점을 변조한 후 buffer 변수의 주소로 ebp+8 지점을 변조하였다. 사용한 shellcode는 다음과 같다.
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80
하지만 공격이 성공하지 않고 core 파일이 생성되었다. core 파일을 gdb로 실행하여 확인해보면 실제 buffer 변수의 주소가 0xbffffc46이다. 이유는 gdb를 통해 실행하면 gdb 환경변수 등과 같은 이유로 실제 주소와 차이날 수 있다.
위와 같이 정확한 buffer 변수의 주소로 바꿔주면 assassin 계정의 password를 확인할 수 있다.