달력

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

'passcode'에 해당되는 글 1

  1. 2017.07.09 [문제풀이] pwnable.kr - passcode
2017. 7. 9. 15:09

[문제풀이] pwnable.kr - passcode Wargames/pwnable.kr2017. 7. 9. 15:09






※ 사전지식 



PLT(Procedure Linkage Table)


외부 프로시저를 연결해주는 테이블이다. 이는 동적 링크 환경에서 함수를 호출할 때 중요한 역할을 하게 된다.



GOT(Global Offset Table)


이 테이블은 프로시져들의 주소를 가지고 있다. 이 테이블은 PLT가 참조하는 테이블이다. 프로그램에서 외부 프로시저를 호출할 때 이 GOT를 참조해서 해당 주소로 점프하게 된다. 해당 테이블은 함수가 처음으로 호출될 때와 그 외에 호출될 때에 다른 값을 가지고 있다. 즉 런타임시 변경되는 값이다. 




우선 해당 문제에 필요한 지식 정도만 공부해도록 하겠다. 

한번에 이런저런걸 너무 많이 검색해서 보니 정리가 잘 안되는 느낌이다. - ㅅ-/



함수를 호출할 때 흐름을 따라가면서 하나씩 살펴보도록 하겠다.



이는 간단히 printf 함수를 두번 호출한 테스트 프로그램이다. 이를 컴파일(not static way)하여 GDB로 분석해보겠따. 



위는 GDB로 메인 함수부분을 디스어셈블링한 내용이다. 빨간 박스로 쳐진 두개의 함수를 따라가면서 호출되는 방법이 어떻게 되는지 확인해보겠다. 



처음으로 함수가 호출될 경우

PLT영역에서 0x80496bc 주소에 있는 값을 참조하여 점프를 하나 이 값은 PLT+6으로 되돌아오게 된다. 그 뒤에 

reloc_offset으로 0x0을 푸쉬하고 0x80482b0으로 점프한다. 



점프한 뒤에 0x80496b4(link_map 구조체 포인터라고 함)를 푸쉬하고 다시 0x80496b8에 있는 값으로 점프를 한다. 여기서 점프하는 곳이 'dl_runtime_resolve' 함수인데 해당 함수에서 실제 puts 함수의 주소를 GOT 영역에 기록한다.


이 과정이 지나고 두번째 puts 함수를 호출하는 과정을 따라가보겠다. 


위에서는 PLT+6의 위치를 가르켰던 GOT가 다른 값을 가진 것을 확인할 수 있다. 이는 실제 puts 함수의 위치를 나타내는 것을 알 수 있다. 


위 과정을 간단히 말하면, 

최초 함수를 호출할 때 PLT가 가리키는 GOT는 다시 PLT+6를 가리켜 GOT가 함수의 주소를 동적으로 할당받을 수 있도록 해주고 동일한 함수를 두 번 이상 호출하게 될 경우 이와 같은 과정이 생략되며 직접적으로 호출이 가능하다. 


해당 과정을 보다 자세하고 심도있게 파헤친 사이트가 있어 아래에 적어놓았다. 관심있으신 분들은 보길 바란다(세상엔 대단한 사람들이 너무 많아). 



사전지식 끝!! 




※ 문제풀이


이제 본격 문제풀이를 들어가도록 하겠다. 





문제는 위와 같다. 여기서 주요하게 살펴볼 점은 login 함수가 되겠다. 



다들 눈치챘겠지만 scanf 함수의 인자로 int 형 변수가 전달되었는데 & 연산자가 누락되었다. & 연산자가 누락되면 변수의 값이 전달되어 그 값을 주소 삼아 쓰기가 가능하게 된다. 


이제 GDB를 통해 함수를 봐보도록 하자. 

소스코드에서 봐도 알겠지만 welcome() 다음에  login 함수가 시작된다. 


우선 welcome 함수를 봐보도록 하겠다. 



소스코드에서 보면 알겠지만 welcome 함수에서 우리가 입력할 수 있는 글자수는 100글자로 제한되어 있다. 즉 우리는 [ebp-0x70]부터 100글자를 입력할 수 있다. 


여기서 간단히 정리하자면 welcome 함수는 단순히 내가 입력한 값을 100글자 이내로 받고 이를 출력해주는 역할을 한다. 해당 함수가 종료되면 바로 login 함수로 진입하게 된다. 



login 함수에서는 [ebp-0x10]에 위치한 값을 scanf 함수의 두번째 인자로 받는다. 이 값은 입력한 값이 저장되는 곳이다. 일단 여기까지 확인하면 문제를 풀기 위해 살펴볼 것은 다 살펴본 것 같다. 


그럼 이제 동작을 시켜볼까나!?



우선 GDB를 통해 프로그램을 동작시키고 welcome함수에서 문자열을 입력받는 곳에 A*100을 입력하고 login함수에서 scanf의 두번째 인자가 위치한 [ebp-0x10]의 값을 확인하도록 하겠다.



짜잔~


이와 같은 현상은 최초에 welcome 함수에서 scanf 함수로 사용자의 입력 값을 입력받았을 때 사용하는 스택 영역과 login 함수에서 사용하는 스택 영역이 중첩되기 때문에 발생하게 된다. 



이대로 동작시킨 다음에 숫자를 입력할 경우는 값을 입력해보면 Segmentation Fault가 나는 것을 확인할 수 있다. 

(이유를 모르시겠다면 위를 다시 확인해주세용!)


그럼 이제 모든게 끝났다. 

어떤 함수의 GOT를 덮어쓸지 결정해서 그 주소를 지정해주고 실행하고자 하는 주소로 덮어쓰면 된다. 


위 내용을 조합해서 문제를 풀면 정답을 풀 수 있다. 




문제풀이 끝!!


포너블이라는 것 자체에 대한 경험이 없다보니 이리저리 참고하면서 풀었는데도 어렵네요.

문제 자체는 간단해보였는데 베이스가 되어야하는 지식이 여럿 필요한 문제였던 거 같습니다. 


우선 조급해하지 말고 공부한다 생각하고 천천히 접근해야할 것 같습니다. 





Reference

[1] PLT와 GOT 자세히 알기 1, https://bpsecblog.wordpress.com/2016/03/07/about_got_plt_1/

[2] PLT와 GOT 자세히 알기 2(with 'yocto'), https://bpsecblog.wordpress.com/2016/03/09/about_got_plt_2/

'Wargames > pwnable.kr' 카테고리의 다른 글

[문제풀이] pwnable.kr - unlink  (0) 2017.07.09
[문제풀이] pwnable.kr - uaf  (0) 2017.07.09
[문제풀이] pwnable.kr - mistake  (0) 2017.07.09
[문제풀이] pwnable.kr - leg  (0) 2017.07.09
[문제풀이] pwnable.kr - input  (0) 2017.07.09
:
Posted by einai