Dork's port

FTZ Level9 Write-up(FTZ Level9 풀이) 본문

Hackerschool FTZ Write-up

FTZ Level9 Write-up(FTZ Level9 풀이)

Dork94 2018. 3. 23. 00:59

안녕하세요! 


문제 9번입니다!


아마 여기서부터 애를 먹는 분들이 많으실 것 같아요!


바로바로바로 BOF문제이거든요! 


BOF는 Buffer OverFlow의 약자입니다! 


관련 문서는 달고나 BOF 문서가 가장 유명해요!


처음보면 어렵기도 하지만 가장 유명한 문서이니 해당 개념에 대해 모르신다면 정독하시는 것을 추천 드립니다!


사실저도 아직 정독까진..


2018/03/22 - [Files] - 달고나 BOF(Buffer Overflow) PDF


서론이 길었네요! 시작해봅시다!


힌트를 보면 어떤 파일의 소스코드를 보여주면서 level10의 권한을 얻으라고 하네요!


우선 buf2와 buf를 각각 10Byte씩 할당해주네요!(char * length of arr)


그리고 친절히 오버플로우가 가능하다는 설명과 함께 buf로 부터 입력을 40만큼 받습니다.


그런데 아래 문장을 보니 buf2랑 비교를해서 "go"이면 setueid와 함께 쉘을 실행시켜 주는군요?


즉 Level10의 권한을 주네요!


setreuid에 관해서는 FTZ Trainner 부분에 있던걸로 기억하므로 여기서는 설명을 생략 하겠습니다.


그럼 우리는 buf에 어떤값을 입력해서 buf2의 시작을 "go"문자로 바꿔야 하는데 언뜻 보기엔 불가능해보입니다.


하지만 따라오시면 아마 알게 될 겁니다!

우선 저 실행파일이 무엇인지 찾아보도록 하죠!


$ find / -user level10 -perm -4000



저기 보이는 의심스러운 파일이 있군요!



먼저 실행시켜 보도록 하겠습니다! 


그러면 "It can be overflow라는 문자열과 함께 특정 문자를 입력받고 그대로 끝나버리네요.

여기서 부터는 디버거 및 어셈블리 언어, 스택의 구조와 C언어에서의 스택이 어떻게 사용되는지를 아셔야 원할이 푸실 수 있습니다.


Write-up에서는 다루기 힘든 내용이니 위의 달고나 문서를 참조하시거나 각자 공부하시고 문제를 푸시는 것을 추천합니다!


질문은 받을 수 있습니다.


자! 그럼 스택에 어떻게 할당되는지 보기위해 gdb로 디버깅을 시도하려 했으나.. "허가 거부됨." 이라는 글자와 함께 gdb로 디버깅 하는걸 막고있군요.


하지만 우리에겐 저 파일의 소스코드가 있습니다!

우선 hint에 있는 소스코드를 복사해서 /home/level9/tmp 폴더에 test.c라는 이름으로 저장하겠습니다.


indent가 이상하긴 하지만.. 파이썬도 아니니까 그냥 넘어가도록 하죠! ㅎ


그리고 gcc를 이용해 해당 코드를 컴파일해준느데 이때 -g옵션을 이용하여 디버깅이 가능하도록 컴파일을 수행합니다,


$ gcc -g -o <실행파일 이름> <소스코드 이름>





그러면 어셈블리를 이용해 main함수에서 어떻게 스택을 이용하는지 보도록 하겠습니다! 


포스팅 수준을 어느정도에 맞춰야할지 고민했으나, 어느정도 어셈블리 및 디버깅에 익숙하다고 가정하고 설명하겠습니다.


$gdb test

(gdb) disass main 


그러면 아래와 같이 main 함수에 대응하는 어셈블리 언어를 볼수있습니다.


저희가 주의깊게 봐야할 부분은 esp 즉, 스택이 어떻게 할당되고 움직이고 함수의 인자로 무슨 주소가 들어가는지 알아야 합니다.

먼저 main+0과 main+1 에서 Stack Frame을 형성한 후 sub를 이용해 0x28만큼 스택의 공간을 할당합니다.


이게 어떠한 변수에 대한 주소가 할당 되었는지는 정확하지 않습니다.


제가 봐온 바로는 소스코드의 시작에서 부터 변수를 선언한 순서대로 스택에 공간을 할당하지만, 그렇지 않은 경우도 많이 보아왔습니다.


또한, 그렇게 되면 BOF의 표적이 되기 쉽기 때문에 일부러 스택에 할당을 뒤섞어도 하는 경우가 있기때문에 아직 소스코드에 첫번째로 선언되는 변수 buf2[10]인지는 정확하지 않습니다.


계속 보도록 하죠!

여길보면 스택에 0xc 만큼 또 할당을 하네요! 

그리고 buf2의 주소를 알수있는 부분입니다! 


밑에보시면 strncmp의 함수를 호출하는 것을 보실 수 있는데요! 그 전에 push를 이용해(스택을 이용해) 인자값을 전달하는 것을 볼 수 있습니다.


전달된 값으론 0x2,0x804856a,0xffffffe8(%ebp)를 전달하는 것을 볼 수 있습니다.


스택에 전달할때에는 소스코드에서 전달하는 인수의 역순으로 전달한다는 것도 알아두세요!


그렇다면 소스코드를 다시볼까요?


if ( strncmp(buf2, "go", 2) == 0 )

 여기서 그럼 0x804856a가 "go"라는 문자열의 주소 0xffffffe8(%ebp)가 buf2의 주소인것을 알 수 있습니다!


그럼 buf의 주소를 알아서 buf2주소까지 입력을 한 후 go를 입력하면 되겠군요! 


그렇다면 buf의 주소는 어떻게 알 수 있을 까요? 아래 소스코드에서 보면 알 수 있습니다.


 fgets(buf,40,stdin);


소스코드 중 fgets의 함수에서 buf를 이용할 때 인자로 주겠네요!


<main + 43>에서 lea 0xffffffd8 (%ebp), %eax부분이 fgets의 인자 중 buf의 인자라고 생각 할 수 있습니다.


그럼 거의 답은 나왔네요!


스택을 한번 간단하게 표현해 보도록 하겠습니다!


이렇게 되겠네요! 그러면 0x28부터 0x18까지의 차이는 0x10 즉 16개이므로 buf에서 부터 16개만큼 의미없는 문자를 채우고 go를 넣으면 정상적으로 쉘 권한이 떨어지겠네요! 


한번 해보죠!


정상적으로 쉘이 떨어졌네요! 그리고 my-pass를 이용해 패스워드를 알면~~

짜라란~ 첫 BOF가 끝났습니다 ㅎㅎ 


어떠셨나요?


다음문제로 가볼까요~?



Comments