LOB - level16 - (assassin->zombie_assassin) fake ebp와 leave ret을 이용한 eip 변조

zombie_assassin의 소스코드

main(int argc, char *argv[])
{
        char buffer[40];

        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }

        if(argv[1][47] == '\xbf')
        {
                printf("stack retbayed you!\n");
                exit(0);
        }

        if(argv[1][47] == '\x40')
        {
                printf("library retbayed you, too!!\n");
                exit(0);
        }

        // strncpy instead of strcpy!
        strncpy(buffer, argv[1], 48);
        printf("%s\n", buffer);
}

argv[1]의 48바이트가 buffer에 덮어씌워진다.

메모리 구조는

[buffer][sfp][ret]이 될 것이다.

ret에서 바로 쉘코드나 system library 함수로 이동을 하여서 쉘을 따고 싶지만 ret은 library의 주소나 스택주소로 주지 못하게 되어 있다.

이때

sfp를 이용해줄 수 있다.
ret이 만약 leave ret 명령어가 있는 곳으로 설정되어 있다면.
leave에 의해서 mov ebp -> esp, pop ebp 가 될 것이고,
ret에 의해 pop eip가 될 것이다.

그래서 만약 [sfp]를 변조해준다면 [ret]이 실행되기 전의 ebp는 우리가 조작한 fake ebp가 될 것이고, [ret]을 실행하여 leave ret이 작동한다면 leave 에 의해서 변조된 ebp를 esp에 넣게 될 것이고, 이 변조된 esp에서 pop ebp를 하고, 그다음 esp+4에서 pop eip를 하게 될 것이다.

결론은 [sfp][ret]을
[fake ebp][leave ret] 으로 바꿔줌으로써

fake ebp+4의 위치에 해당하는 명령어로 점프할 수 있게 된다. (fake ebp 주소에 있는 값은 pop ebp에 의해 소거되고, 다음 fake ebp+4의 위치에 있는 값이 pop eip에 사용된다.)

위와 비슷한 방법으로

fake ebp를 준다음 [ret]은 함수의 +3 위치로 적어주면 함수 시작시 발생하는 push ebp, mov ebp -> esp, 가 발생하지 않기 때문에 우리가 원하는 ebp를 주고 함수를 실행시켜줄 수 도 있다. esp는 조작해 줄 수 없으므로 esp 기반으로 동작하는 함수는 사용하지는 못할 수도 있다.

댓글