tmxklab
[FTZ] Level12 풀이 본문
1. 문제확인
1) 사용자 및 패스워드 : level12 / it is like this
2) 파일확인
3) hint 코드 설명
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main( void )
{
// char형 str변수 256바이트 할당
char str[256];
// 실제 사용자 ID와 유효 사용자 ID 3093로 설정
setreuid(3093, 3093);
printf("문장을 입력하세요.\n");
// 사용자 입력을 통해 str변수에 저장
gets(str);
printf("%s\n", str);
}
- 프로그램 실행시에 gets()를 통해 사용자의 입력을 받을 수 있음
- str배열의 크기(256bytes)보다 더 큰 입력 값을 넣을 수 있음 -> bof취약점 존재
2. 접근방법
1) attackme 디버깅(참고 : $ebp, $esp는 왼쪽 명령어 수행 이후 값)
- 1~2번 : 함수의 프롤로그로 함수가 실행될 때 그 이전의 ebp(sfp)를 스택에 push하고 현재 esp를 ebp에 저장 -> 수행 이후 ebp와 esp는 같은 위치를 가리킴
- 3~4번 : sub esp, 0x108(264bytes)를 통해 esp값 0xbffe258 - 0x108 = 0xbfffe150을 esp에 저장 -> ebp로 부터 264bytes 스택 공간 확보(스택은 높은 주소에서 낮은 주소로 쌓임)
- 따라서, main함수 실행 후 스택 프레임을 형성한 뒤 char str[256]선언으로 인해 264bytes공간 확보(str배열 크기의 256bytes + dummy값 8bytes)
※ 참고
함수의 프롤로그는 다음 두 명령어를 뜻함
① push ebp
② mov ebp, esp
- 4~6번 : push 0xc15는 setreuid()의 인자 값인 3093을 의미(함수가 실행하기 전에 인자 값을 먼저 push하고 함수 실행) -> 인자 값 2개를 받기 위해 먼저 esp를 0x8(8bytes)만큼 늘려주고 push 0xc15를 두 번 수행(push 한 번에 4bytes만큼 쌓임)
- 7~8번 : call 명령어는 call 다음에 오는 접근할 함수(setreuid())의 주소로 이동하여 실행, add esp, 0x10을 통해 4~7번에서 변경된 esp위치를 원래대로 복귀 -> 즉, 3번 명령어 수행이후의 esp위치와 같음
※ 참고
call 명령어는 다음 두 가지 동작을 수행함
① push eip : call 다음 명령줄의 주소 값을 스택에 저장, 접근할 함수로 진입하기 전에 되돌아올 명령어 주소를 저장함(여기서, EIP값을 Return Address라고 함)
② jmp [접근할 함수 주소] : eip주소 값을 스택에 저장하였으면 접근할 함수 주소로 분기하는 것을 의미
- 9~10번 : 첫 번째 printf()를 수행하는 부분으로써 10번 push 0x8048538에서 의미하는 주소 값을 이용하여 gdb에서 "x/s 0x8048538"을 입력하면 printf()에 출력될 "문장을 입력하세요.\n"을 확인
- 11~12번 : call명령어로 printf()수행 이후 esp값 원래대로 복귀
- 13~15번 : lea는 mov 명령어와 달리 좌측(레지스터)에 우측의 주소 값을 입력하는 명령어(mov명령어는 좌측에 우측의 값을 입력), [ebp-264]에 위치한 str변수의 주소 값을 eax에 복사한 뒤 주소 값을 스택에 push하여 gets()의 인자로 사용
- 16~17번 : call명령어로 gets()수행 이후 esp값 원래대로 복귀
- 18~21번 : 두 번째 printf()의 인자 값 2개 입력 받음(인자 값은 함수의 오른쪽부터 왼쪽 순으로 스택에 push)
- 22~23번 : call명령어로 printf()수행 이후 esp값 원래대로 복귀
- 24~25번 : 함수의 에필로그
※ 참고
함수의 에필로그는 다음 두 명령어를 뜻함
① leave
② ret
※ 참고
leave와 ret명령어는 두 가지 동작을 수행함
1) leave
① mov esp ebp : esp에 ebp의 주소를 넣어 ebp와 esp가 동일한 주소 가리킴(스택 프레임 정리)
② pop ebp : ebp를 스택에서 제거
2) ret
① pop eip : eip를 스택에서 제거함으로써 프로그램 실행 이후 다음에 실행될 명령 주소 값 가르킴
② jmp eip : eip가 가리키는 명령어의 주소로 분기
2) 스택구조
- gets()가 수행하는 어셈블리어를 보면 eax에 [ebp-264]의 주소 값을 가져오므로 [ebp-264]에 str변수 존재
- 하지만, str배열은 256bytes만큼 선언하였으므로 str변수와 SFP사이에 8bytes만큼의 dummy값이 존재함을 추정
3) 결론
- 사용자가 입력받을 수 있는 부분은 gets()이며 str배열의 크기(256bytes)보다 더 크게 입력하여 ret주소 값이 위치한 부분에 쉘 코드 수행
- str배열에 268bytes(str[256] + dummy[8] + sfp[8])만큼 아무 값으로 넣고 그 다음에 쉘 코드 주소 넣으면 ret부분에 쉘 코드 사용하게 됨
3. 풀이
1) 사용할 쉘 코드 주소 값을 환경변수로 등록
2) 환경변수 SHELLCODE의 주소 값 확인
3) bof수행
- python프로그램을 사용하여 \x90(1byte)를 268만큼 출력 -> SFP까지 덮기 위해
- RET주소에 $./getenv를 통해 출력된 쉘 코드 주소 값을 채워 넣음(리틀 엔디안 방식으로)
'War Game > FTZ' 카테고리의 다른 글
[FTZ] Level16 풀이 (0) | 2020.01.12 |
---|---|
[FTZ] Level15 풀이 (0) | 2020.01.12 |
[FTZ] Level14 풀이 (0) | 2020.01.12 |
[FTZ] Level13 풀이 (0) | 2020.01.12 |
[FTZ] Level11 풀이 (0) | 2020.01.12 |
Comments