[어설픈] 해커스쿨 FTZ Level 16 문제풀이

2019. 2. 5. 23:44System Hacking/FTZ

안녕하세요! 

오늘은 FTZ Level 16번 

문제풀이를 하겠습니다!


문제를 보니 아래와 같이 나와있네요!


shell함수가 선언 되어있고!

shell 함수를 실행시키면 

->(real effective) uid가 Level 17로 상승한다

-> (Level 17의 권한으로) 쉘을 실행한다


printit함수도 선언되어 있네요!

printit함수는 Hello there!를 출력해주고 끝나는 함수네요!


그 다음에 main 함수를 보면


1. int 형 변수 crap을 선언하고!


2. void형의 함수 포인터 call에 printit의 주소를 넣네요!

[원래 *call 이거면 call 포인터 변수인데 

(*call)( ) 이렇게 함수 ( )를 포함하고 있는 꼴이라 함수 포인터에요!]


3. char 형의 buffer 20 byte를 선언하고


4. fgets 함수로 stdin(standard input)방식으로 48byte 입력받아서 buf에 넣네요!

당연히 buf는 20byte니 오버플로우가 발생하겠죠! 


5. 함수포인터 call을 호출하네요!


[ 함수 포인터는 call( )이렇게 

함수포인터 이름 뒤에 괄호를 붙이면 ( )

해당 함수를 호출 합니다!


함수 포인터에 다른 함수의 주소를 담고 싶으면

괄호( )를 떼고 대입연산자 =로 넣어주시면 되요!


ex) call에 printit이 아니라 shell 함수 의 주소를 넣고싶다!

-> call=shell; 

그리고 call ( )을 실행하면 shell 함수가 실행됩니다! ]



일단 여기까지 보고 어떻게 exploit할지

생각을 해보겠습니다!


1. 오버플로우를 통하여 흐름을 다르게 제어해야 한다


2. 문제를 풀려면 level17의 권한을 얻어야 하는데 그럴려면  shell( )를 무조건 이용


3. shell을 어떻게 호출할까 보니 call 함수 포인터에 printit대신 shell 주소를 넣으면 끝!


4. 스택상황을 보니  ----------> buf[20] 

               call (4byte=주소값이니까)

crap (4byte=int니까)


5. buf에 넘치게 입력을해서 call 함수포인터의 값을 바꾸면 끝나겠네!


그래서 정확히 얼만큼 넣어야 하는지 

shell( )의 주소는 어딘지

알기 위해서! 

GDB를 켰습니다!


3번째 줄을 보니

sub $0x38, %esp 

0x38= 56이네요!


그리고 맨 마지막

call( )을 호출할 때 

*%eax 값을 호출하는데


바로 위 줄을 보면

ebp+0xfffffff0의 값을 eax에 옮기니까 


저희가 넘치게 입력하고 ebp+0xfffffff0 값을 확인하면

얼만큼 넣어야 call 함수를 조작 할 수 있는 지 알겠네요!


그래서 break point를 걸어놓고!

여기는 main+49라고 되어있는데 

main+39로 바꿔서 보시면 될 것 같아요!


그리고 attackme에다가

 a를 40개 주고 이후에

4개씩 b,c,d,e,f,g,를 줬습니다!


왜 a 40개냐?

왜냐하면 그전까지 a를 20개 넘게 주었는데도

계속 입질이 안와서 계속 넣다가 이렇게 됐습니다!


입력한 다음에 위에서 제가 말씀 드린대로!

%eax에 주소값 넘기기전에 

어떤 주소값을 넘기는지

$ebp+0xfffffff0 값을 확인해보니

0x62626262(bbbb)네요!

 

즉 41,42,43,44위치가 call 함수포인터 공간이네요!


자 그럼 저희가 call 함수 포인터 위치에 넣어야 할 것은 무엇?

당연히 지금은 printit 함수 주소가 들어가 있으니

shell함수의 주소를 넣어야 겠죠!


그래서 gdb에서 

disas shell을 입력하면

제일 앞에 뜨는 0x080484d0이 

shell의 시작주소네요!


그러면 이제 구할꺼 다 구했네요!

call 함수 포인터의 값은 41~44번재 입력값에 영향을 받고

41~44번째 입력값에 0x080484d0를 

little endian을 넣으면 끝나겠네요!



그래서 바로 exploit 하려고 

아래와 같이 짜볼 수 있습니다!


물론 앞에 NOP \x90이나 a로 40개 채울 수 있는데

그렇게 굳이 하지 않아도 0x080484d0를 11번 넣어도

44byte가 되니까 


그리고 argv 형식이 아니라 

fgets로 입력을 받으니 저희가 

| 을 사용해야겠죠?



그래서 입력하니 바로 아래와 같이 

exploit이 되고 비밀번호가 뜨네요!


고생하셨습니다!