[어설픈] LOB 12번 golem 문제풀이

2019. 3. 30. 23:18System Hacking/[LOB] Hacker School

안녕하세요!

오늘은 LOB 12번 문제인

golem 문제풀이를 해보도록 하겠습니다!


문제의 소스는 아래와 같습니다!

이번에 keyword에 FPO라는게 있네요!

-----------------------------------------------------

※FPO(Frame Pointer Overflow)

1. ebp(=frame pointer)에서 1byte overflow가 일어나야함

2. 서브함수(=main 함수 말고 또 다른 함수)가 필요함


1의 이유는 1byte overflow가 일어난다면

ebp의 첫 번째 byte가 영향받죠!

 ebp근처에 있는 버퍼나, ebp 근처의 이웃으로 

ebp의 조작이 가능함!


왜 그러냐? 

직전 문제 vampire에서 저희가 ret address에

\x99\xff\xff\xbf를 줬죠?

여기서 \x99부분(ebp 첫 번째 부분)이 조작가능하다고 보시면 돼요!


그러면 0xbfffff00~0xbfffffff까지 ebp의 주소를

조작 가능하겠죠?


Question : ebp를 조작해서 뭐하는데...?


Answer: ebp를 조작하면 ret을 조작 할 수 있어요!

What? 什么? なに? 뭐라고?


왜냐하면 일반적인 프로그램의

에필로그 할 때의 스택을 보시면


[스택 상황]

ebp

  return address


이렇게 붙어있잖아요!

leave 하기 직전에는

ESP가 원래  다른 곳을 가리키다가 


leave 할 때

mov esp,ebp (이 부분에서 아래처럼 esp가 ebp를 가리킴) 


[스택 상황]

ESP->ebp

   return address 


그리고 pop ebp를 하면서

ESP가 아래처럼 return address를 가리켜요!


[스택 상황]

ESP -> return address


그리고 ESP는 현재 ret을 가리키고 있으니

return(pop eip => jump eip)를 하잖아요!


1. ESP가 가리키는 것을 eip로 pop한다(=옮긴다)

2. 그 eip에 있는 주소로 jump 뛴다


즉,return address의 위치= EBP+4라는

관계식이 성립하는거죠!

ret_address는 ebp에 종속적이다!


그래서 제가 결국 말하고 싶은 것은 

여기서 이 EBP의 위치를 저희가 바꾸면

return address도 위치가 바뀌게 된다!


그럼 바뀐 return address의 위치에 저희가 원하는 값을 넣으면!

exploit가 가능합니다!


그리고 2번째로 sub 함수가 왜 필요하냐면!

위와 같이

ebp를 저희가 sub함수에서 조작한 다음에

 pop을 하면

main 함수의 ebp가 조작됩니다!

(= main의 return address가 조작가능)

main 함수의 saved ebp 말고요!



FAKE EBP에서는 EBP를 조작하고

Return Address에 leave, return gadget을

넣어서 leave를 한번 더하게 합니다!

그럼 저희가 조작한 ebp 값으로 

esp가 이동하기 때문이죠!!!

(물론 이 경우는 ebp 1byte가 아니라 ebp 전체를 조작 가능함)


근데 여기서는 sub 함수가 없으면 

1byte overflow는 

main 함수가 종료되면 실행될 함수의 ebp를

 1byte 만큼만 조작 가능합니다ㅠㅠㅠㅠ

(=saved ebp인거죠 main 함수의 ebp가 아니라)


★ EBP / Saved EBP 오해하실까봐 ★


(1) 그냥 main 함수 EBP

gdb에서 main함수에 break 걸고 info registers 했을 때 나오는 ebp가 저희가 말하는 main 함수 ebp


(2) main 함수의 Saved EBP

main 함수 스택에서 

buffer [40]

ebp <---

ret_address 

저 화살표가 saved ebp요!

 

fake ebp에서 파생된 개념인데!

(구글에서 추가적을 공부하시면 될 것 같습니다!)


이렇게 해서 긴 설명 끝에 FOP에 대해서 알아봤습니다!


사실 이번 문제코드는 되게 간단해요!

FOP개념에서 말한 것 처럼!

main 함수에서 sub함수인 problem_child( )를 실행하는데

problem_child가 1byte overflow가 일어나요!


그럼 일단 gdb를 켜서 

버퍼의 위치를 확인해봐야 겠죠?

거기에 쉘코드 넣고, 이것저것 할테니까요!


여기는 problem_child 함수를 disassemble 한거에요!

problem_child가 leave할 때를 확인해 봐야겠네요!



그래서 buffer의 위치를 확인해봤는데!

0xbffffaa4네요!

제가 0xbffffaa0을 확인한 이유는 

지난번 문제에서도 버퍼 주소 바로 직전 주소에

버퍼의 주소가 담겨있어서 봤습니다!


근데 이번에도 똑같이 담겨있네요!

0xbffffaa0에 0xbffffaa4가 담겨있잖아요!


그리고 여기서 저희가 생각해야 될 부분이

problem_child의 saved ebp가

0xbffffa00~0xbffffaff 사이 값을 가져야 해요!


만약 0xbffffb??이면 

저희가 아무리 뒤에 두 자리 조작해도 

버퍼 -4 주소값으로 리턴 못하니까요! 

 


근데 다행히도 여기에 스크린 샷은

안 올렸는데, 0xbffffa00~0xbffffaff 범위 사이네요!


그래서 바로 아래와 같이 payload를 주고 

실행시켜 봤습니다!


25byte shellcode + 15byte \x90 + 0xbffffa9c(여기로 해야 esp가 pop ebp 하고 0xbffffaa0을 가리킴)

근데 제대로 안되네요.....

 

분명히 제대로 했는데...


그래서 이번엔 앞선 문제에서 깨달았던

' main 함수의 leave, ret에 breakpoint를 두고 스택을 확인하자! '

를 실행에 옮겼습니다!


그랬더니 buffer의 주소가 조금 다르네요!

그래서 앞에서 줬던 ebp 주소를 

0xbffffaa0 ---> 0xbffffab0으로 바꿨습니다!


그리고 아래와 같이 다시 실행하니!

제대로 쉘이 따지고

비밀번호가 나오네요!


고생하셨습니다!