buf[32] + SFP - Overflow
puts@plt + 6 (=puts@got)
pop ret
scanf@got
scanf@plt
pop pop ret
%s
이 부분에서 puts@plt + 6가 실행되서 scanf의 주소를 출력한 다음 pop ret이 실행되어서
pop으로 인해 esp가 scanf@got쪽으로 옮겨지고 ret으로 인해 scanf의 주소가 eip에 들어가고 그대로 eip의 scanf가 실행되어버리지 않나요?
제대로 셸코드가 실행되려면 scanf@got는 넘어가고 scanf@plt가 실행되어야 하는 것으로 보이는데 ㅠㅠ
overflow가 발생하였을 때 main함수에서 ret을 할 당시의 스택 상태는 다음과 같습니다.
puts_plt + 6
pop_ret
scanf_got
scanf_plt
pop_pop_ret
%s
ret으로 인해 puts_plt+6으로 점프하게 되고 puts_plt+6을 실행하는데 puts_plt+6은 pop_ret
을 return해야할 주소, scanf_got를 전달받은 인자로 생각하게 됩니다.
그럼 puts함수는 scanf의 주소를 출력하고 pop ret
으로 점프하게 됩니다. 이때 스택의 상태는 아래와 같습니다.
scanf_got
scanf_plt
pop_pop_ret
%s
pop ret
으로 점프했기 때문에 stack에서 먼저 pop을 진행하여 scanf_got를 제거한 뒤 ret으로 인해 scanf_plt로 점프하게 됩니다.
이때 scanf는 %s를 format_string으로 사용하고 %s 이후에 오는 주소에 입력을 받게 됩니다. 해당 예제의 경우 스택의 상태가 아래와 같습니다.
pop_pop_ret
%s
scanf_got
scanf_plt
0xdeadbeef
scanf_got+4
따라서 scanf_got에 사용자의 입력을 write하게 되고 이후 return을 하게 되면 pop_pop_ret
으로 뛰게 됩니다.
pop을 2번하게 되면 스택의 상태는 아래와 같게되고
scanf_plt
0xdeadbeef
scanf_got+4
ret으로 인해 scanf_plt로 점프하게 됩니다.
해당 예제에선 사용자의 입력이 system함수 주소 + /bin/sh\x00
이였기 때문에 scanf_plt에는 system함수의 주소가 들어있게 됩니다.
system함수가 실행되면서 scanf_got+4를 인자로 사용하게 되는데 scanf_got+4에는 /bin/sh
가 들어있으므로 system('/bin/sh')
를 호출한 것 처럼 shell을 획득할 수 있게 됩니다.