tmxklab

[FTZ] Level12 풀이 본문

War Game/FTZ

[FTZ] Level12 풀이

tmxk4221 2020. 1. 12. 21:19

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는 왼쪽 명령어 수행 이후 값)

main() 시작

  • 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

 

setreuid()

  • 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주소 값을 스택에 저장하였으면 접근할 함수 주소로 분기하는 것을 의미

 

첫 번째 printf()

  • 9~10번 : 첫 번째 printf()를 수행하는 부분으로써 10번 push 0x8048538에서 의미하는 주소 값을 이용하여 gdb에서 "x/s 0x8048538"을 입력하면 printf()에 출력될 "문장을 입력하세요.\n"을 확인
  • 11~12번 : call명령어로 printf()수행 이후 esp값 원래대로 복귀

gets()

  • 13~15번 : lea는 mov 명령어와 달리 좌측(레지스터)에 우측의 주소 값을 입력하는 명령어(mov명령어는 좌측에 우측의 값을 입력), [ebp-264]에 위치한 str변수의 주소 값을 eax에 복사한 뒤 주소 값을 스택에 push하여 gets()의 인자로 사용
  • 16~17번 : call명령어로 gets()수행 이후 esp값 원래대로 복귀

두 번째 printf()

  • 18~21번 : 두 번째 printf()의 인자 값 2개 입력 받음(인자 값은 함수의 오른쪽부터 왼쪽 순으로 스택에 push)
  • 22~23번 : call명령어로 printf()수행 이후 esp값 원래대로 복귀

main() 끝

  • 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