Off-By-One
- 경계검사에서 하나의 오차가 있을 때 발생한다.
- 버퍼의 경계 계산 혹은 반복문의 횟수 계산시 < 대신 <=을 쓰거나,
0부터 시작하는 인덱스를 고려하지 못할 때 발생한다.
드림핵의 예제코드를 살펴보면
buf의 크기는 16인데
for(i = 0; i <=sz; i++)에서 17번의 반복을 수행하는 것을 볼수있다.
따라서 off by one이 발생한다
17번의 'A'를 입력하면 오버플로우가 발생하는 것을 볼 수 있다.
FPO(Frame Pointer Overflow)
- 기존의 stack buffer overflow는 ret의 주소를 변경했다.
- 하지만 FPO는 ret위에 있는 sfp를 변경시켜 결론적으로 IO를 변경하는 것이 목표이다.
- SFP영역에서 최소 1바이트의 overflow가 발생해야한다
- 메인 함수 이외의 서브 함수가 필요하다.
함수의 에필로그
FPO를 이해하려면 함수의 에필로그를 이해 해야한다.
험수의 에필로그는
leave, ret으로 구성되어있다.
그리고
leave는
mov esp, ebp
pop ebp
를 수행하며,
ret은
pop eip
jmp eip
를 수행한다.
1bye overflow 발생
먼저 1byte overflow가 발생하면 위와 같이 sfp의 하위 첫 바이트가 변경된다.
서브함수의 에필로그
서브함수의 mov esp, ebp
이후 mov esp, ebp가 실행되면 esp는 ebp의 위치로 이동한다.
서브함수의 pop ebp
sfp의 값이 ebp로 팝 되어 ebp가 변조된 값으로 이동하게 된다.
서브함수의 pop eip, jmp eip
pop eip, jmp eip가 실행되면 서브함수의 ret에 저장된 원래의 실행 흐름(main)으로 돌아가게 된다.
메인함수의 에필로그
메인함수의 mov esp, ebp
mov esp, ebp가 실행되면 esp가 변조되었던 ebp의 위치로 이동하게 된다.
메인함수의 pop ebp
pop ebp가 실행되면 0xbffffaa0에 저장되어있던 어떤 값으로 ebp가 이동하게 된다.
메인함수의 pop eip, jmp eip
pop eip, jmp eip가 실행되면 eip에 0xbfffaa4에 저장되어있던 주소에 있는 명령어가 실행된다.
만약 여기에 shell code가 있었다면 셸이 실행된다.
여기에서 처음에 sfp를 변조할 때 실행시킬 명령어의 주소 - 4에 위치한 값으로 sfp를 변조해야 한다는 것을 알 수 있다.
(pop eip를 할 때 esp는 4만큼 증가하기 떄문에)