FTZ 11 Level
ID : level11
Passwd : what!@#$?
접속해서 ls 명령어를 이용해서 디렉터리와 파일을 보면 attackme라는 실행 파일과 hint라는 파일이 있습니다. attackme를 보면 level12의 setuid가 걸려있는 걸 확인할 수 있습니다.
cat 명령을 이용해서 hint를 열어보면 attackme의 소스가 나옵니다. main 함수에서 인자를 받고 strcpy를 이용해서 str이라는 배열에 복사하고 printf 함수로 출력하는 것을 확인할 수 있습니다. 하지만 strcpy라는 함수는 얼마나 복사할지 길이의 제한을 두지 않기 때문에 프로그래머가 고려하지 못한 오류가 발생할 수 있습니다.
이렇게 배열 크기보다 작은 크기의 문자열을 입력하면 프로그램은 정상적으로 돌아가지만,
배열보다 큰 크기의 문자열을 입력했더니 입력한 문자열이 출력되기는커녕 Segmentation fault라는 의도하지 않은 문자열이 출력되었습니다. 그럼 Segmentation fault는 뭘까요?
세그멘테이션 결함(Segmentation Fault)은 컴퓨터 소프트웨어의 실행 중에 일어날 수 있는 특수한 오류이다. 세그멘테이션 위반, 세그멘테이션 실패라고도 하며, 세그폴트(Segfault)로 줄여서 쓰기도 한다. 세그멘테이션 결함은 프로그램이 허용되지 않은 메모리 영역에 접근을 시도하거나, 허용되지 않은 방법으로 메모리 영역에 접근을 시도할 경우 발생한다.
(출처 : 위키백과)
즉, 버퍼보다 큰 크기의 문자열을 입력했더니 잘못된 주소에 접근하게 된 것입니다.
Buffer Overflow가 일어난 것입니다. 입력한 문자열이 Buffer의 크기보다 커서 넘쳐 흐르게 된 것이죠.
attackme라는 실행 파일을 디버깅 하기 위해서 tmp 디렉터리로 옮기겠습니다.
그리고 GDB를 이용해서 디버깅 해보도록 합시다.
gdb 뒤에 –q 옵션을 붙인 이유는 –q 옵션 없이 gdb를 실행하면 몇 줄의 설명 같은 게 나오게 되는데, 그 설명을 생략하기 위함입니다.
set disassembly-flavor intel 이라는 명령을 한 이유는 디스어셈블 방식이 AT&T와 Intel 방식으로 나뉘는데 Intel 방식이 레지스터 + offset 에서 offset을 10진수로 표현해주고 mov 인자1 인자2 와 같은 명령이 있을 때, 인자2를 인자1에다가 move 시켜줍니다. 즉, C언어와 같이 뒤에서 앞으로 읽을 수 있어서 편하게 어셈블리 코드를 해석할 수 있습니다.
main 함수를 디스어셈블 해보면 main+0과 main+1에서 함수 프롤로그가 끝나고 sub esp, 0x108 명령으로 스택 프레임을 생성합니다. 0x108은 10진수로 264입니다. 아까 str 배열의 크기가 256byte 였던걸 감안하면 dummy 값의 크기는 264-256=8(byte)라는 것을 확인할 수 있습니다. dummy는 컴파일러가 넣어주는 쓰레기 값입니다.
메모리 구조는 다음과 같습니다.
| Buffer (256) | dummy (8) | SFP (4) | RET (4) |
SFP는 사용하지 않으니 payload는 NOP*243 + 25byte 셸코드 + 앞의 NOP 주소 중 하나
왜 NOP을 사용하느냐, NOP은 No Operation의 약자로 만나면 프로그램의 진행에 상관 없는 그냥 아무런 의미 없는 행동을 하고 다음 명령으로 넘어가게 됩니다. 그럼 앞의 NOP 주소 중 어딘가로 Return Address를 변조하기만 하면 NOP을 쭉 실행하다가 셸코드를 만나 쉘을 실행하게 됩니다.
그런데 셸코드 뒤에 공간이 필요합니다. 그 이유는 아래 블로그에 설명되어 있습니다.
셸코드 뒤에 16byte의 여유 공간을 주도록 하겠습니다.
payload : Nop*227 + 25byte 셸코드 + 앞의 NOP 주소 중 하나
그럼 NOP 주소가 어딘지 구해보겠습니다.
strcpy 함수가 끝난 후에 breakpoint를 걸어줍니다.
구성한 payload를 넘겨줍니다. AAAA는 변조된 Return Address가 들어갈 위치입니다.
메모리를 확인해보면
노란 부분은 str 배열의 시작 주소, 빨간 부분은 셸코드, 파란 부분은 Return Address 입니다. NOP 중 어느 주소에 돌아가든 상관 없으니 0xbffff3a0을 리틀 엔디안 방식으로 전달하겠습니다.
payload : ./attackme `python –c ‘print “\x90” + “\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80” + “\xa0\xf3\xff\xbf”’`
원본 파일에 payload를 넘겼습니다. 근데 쉘은 실행이 안 되고 세그폴트가 났네요.
그 이유는 Ledhat 9.0에서 ASLR이라는 기법을 지원하기 때문입니다. ASLR는 랜덤 스택으로 스택 영역의 주소가 일정하지 않고 변동이 있다는 것을 뜻합니다. 그래서 계속 공격해보면
쉘이 실행됩니다.
감사합니다.
'System&Write up > FTZ' 카테고리의 다른 글
FTZ level16 -> level17 Write up (0) | 2017.09.25 |
---|---|
FTZ level15 -> level16 Write up (0) | 2017.09.25 |
FTZ level14 -> level15 Write up (0) | 2017.09.25 |
FTZ level13 -> level14 Write up (0) | 2017.09.25 |
FTZ level12 -> level13 Write up (0) | 2017.09.24 |