달력

5

« 2024/5 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31


※ 사전지식 


SFP (Stack Frame Pointer)


SFP 란 함수를 호출할 때 함수의 시작부분에 있는 몇 개의 명령어로 발생하게 된다. 

보통 함수 프롤로그(prologue)부분에서 EBP 레지스터의 위치를 보전하기 위해 스택에 저장되는 값이다. 


해당 과정을 간단히 살펴보자. 


만약 함수 A에서 함수 B를 호출하면 일반적으로 함수 B에 들어가자마자 아래와 같은 명령어를 실행한다. 


  PUSH EBP

  MOV EBP, ESP


해당 과정을 거치면 스택은 아래와 같은 모양을 가진다. 


[그림 1]


어셈블리어를 보면 알겠지만 SFP 위치에는 이전 함수에서 사용하던 EBP 주소가 저장된다. 

그래서 함수가 기능을 다하고 복귀할 때 본래의 EBP 주소를 유지할 수 있는 것이다. 



SFP Overwrite


이는 말 그대로 SFP에 값을 덮어쓸 수 있어 함수의 에필로그(Epilogue) 부분에서 EBP를 변조할 수 있는 취약점이다. 

우선 에필로그는 보통 아래와 같은 형태를 볼 수 있다. 


 MOV ESP, EBP

 POP EBP

 RET   


 or 


 LEAVE

 RET


이 과정을 거칠 경우 SFP의 값이 EBP로 전달되어 이 후 실행 흐름에 문제를 줄 수 있다. 



사전지식 끝!





※ 문제풀이 


해당 문제는 값을 입력할 때 세그먼트 뻑이 나서 금방 감을 잡을 수 있었다. 


흐름을 간단히 말하면 아래와 같다. 


1. 인증을 위한 값을 요구한다.  - main 

2. 내가 입력한 값을 Base64Decode 함수를 통해 Base64 디코딩을 수행한다.  - main

3. "2번"에서 얻어진 값을 이용해 자체 md5 함수를 활용하여 해시 값을 구한다.   - auth

4. 프로그램에 내장되어 있는 해시 값과 같은지 검사하고 같으면 "correct" 함수를 호출한다.  - main

5. correct 함수 내부에서 input 변수에 들어있는 값을 확인하고 같으면 /bin/sh 을 호출한다.  - correct



여기서 취약점은 auth 함수에서 발생하게 된다. 


[그림 2]


쓸때없이 memcpy 인자로 전달되는 스택 값에 0x0Ch 값을 더하는 바람에 SFP 가 덮어써진다. 

그 뒤 auth 함수 에필로그 부분에 SFP 값이 EBP로 쓰여지고 

main 함수 에필로그에서 EBP가 다시 ESP로 이동할 때 우리는 실행 흐름을 바꿀 수 있다. 

ESP가 가리키는 지점의 값이 RET 명령어를 만나면 해당 값을 EIP로 옮겨놓기 때문이다. 




[그림 3]


나는 correct 함수 내에 빨간 박스를 쳐 놓은 위치로 분기하기로 결정했다(가장 심플). 


따라서 익스플로잇 코드는 아래와 같다. 


 import base64


correct = "\x78\x92\x04\x08"     # correct 함수 내에 /bin/sh 호출 부분

stack = "\x40\xeb\x11\x08"       # input 변수 위치 중 correct 함수 주소를 담고 있는 위치 


payload = "AAAA" + correct + stack 

data = base64.b64encode(payload) 

print(data) 


문제풀이 끝!



처음에는 스택 위치만 활용하려다가 시간을 좀 빼앗겼다. 

값을 저장할 수 있는 곳은 스택 뿐만이 아니라는 것을 잘 기억해놓자. 







:
Posted by einai