주정도 걸려서 푼 문제이다.
이 문제를 풀기위한 고비가 크게 3번 있었다그 고비를 중심으로 설명하겠다.
 

먼저 문제 프로그램을 살펴보자



(프로그램)


이 프로그램은 입력을 2가지 방식으로 받는다. First Input에서는 스택에 입력을 저장하고, Second Input에서는 heap영역에 값을 저장한다그리고 3번 Delete로는 값을 삭제하는데 스택에 저장한 값은0으로 채우고힙영역은 free로 메모리 할당을 해제하여 삭제한다. Print는 저장했던 값을 출력하고 Exit는 프로그램을 종료한다.
 
1번째 고비
프로그램이 단순한 executable 파일이 아니다??...

이 프로그램은 shared object 파일이었다.



(파일 정보)



So 파일은 동적으로 프로그램 실행할 때 메모리에 로딩하는 파일로만 알고 있었다물론 그런 파일이지만 이 프로그램 단독으로 실행되는 줄은 몰랐다.
 
왜 이게 고비였냐 하면메인함수로 찾아가기가 힘들었다.
게다가 심볼이 없다. Start address를 찾아서 브레이크를 걸고 실행하여 일일이 뒤져가 main 함수를 찾아내었다.
 
*  Main 함수까지 가는법.
먼저 gdb로 열고 한번 그냥 실행해 주어야한다아까 말했든 이 파일은 so 파일이어서 처음에는 메모리에 존재하지 않는다… 한번 실행해주고 중단 시킨 후 재실행할 때 break를 잡아준다.

Break 잡아주는 위치는 _dl_start_user 여기로 잡아준다이건 내가 찾아낸 부분인데 이 부분 전에 starter 어쩌구 함수에서 실행이 되고 이 함수로 넘어오는데 여기에 break 잡아준다.




(main 찾아가기(1))




main 찾아가기(2)



그 후 위 사진처럼 저 위치에서 si로 함수 안으로 들어가준다.



main 찾아가기(3)



여기 call rax에서 si로 함수 안으로 들어가주면 여기서부터 main 함수이다.



main 함수



Main 함수드디어찾았다.! (여기서 첫번째 고비를 넘겼다.)

(여기 main함수 까지 찾아오는데 정말 오래걸렸다.)
 
두번째 고비
스택과 힙힙은 취약점이 없어보이는데??...
 
두번째 고비는 힙 영역에 취약점이 없어 보인다는 점이었다스택 영역은 스택 카나리가 존재해서 bof를 생각도 안했다그리고 heap영역에는 다양한 취약점이 존재한다는 걸 알고 있었기에 노려보려 했지만 쉽지 않았다.
 
그 이유는 heap영역에 취약점은 기본적으로 heap overflow에 기반했다하지만 여기서는 입력할 데이터 수를 받고 그 데이터길이만큼 malloc으로 할당해준다그리고 그 영역에 read함수를 통해서 해당 데이터 길이만 입력을 받기 때문에 overflow가 일어나기 힘들었다.
 
여기서 한참 방황한뒤 취약한 틈새를 발견하게 되었다바로 print하는 부분이다.

바로 입력한 문자열을 출력할 때 null 값까지 쭉 출력한다는 점을 이용하여 스택영역에 값들을 노출 시킬수 있겠다는 생각이 들었다.




(스택 모양)


위 빨간 영역에 바로 버퍼의 주소이다스택영역에 입력할 수 있는 길이가 130까지 되므로 충분히 카나리를 노출 시킬 수 있고 ret 주소 까지 덮어쓸 수 있다.
 

카나리를 노출시킬 수 있으면 카나리 위치에 카나리를 넣을 수 있고 그렇다면 stack overflow를 할 수 있다는 생각이 들었다.



(카나리 구하기 함수)



바로 여기서 이 부분을 파고 들기 시작했다.
 
3번째 고비
쉘을 따기 위해서는 system함수를 불러야하고 인자를 넘겨야하는데 어떻게
 
3번째 고비는 인자 문제였다.
Ret 까지 system 함수를 호출하는건 문제가 없었다.
하지만 인자를 넘겨주는데 문제가 있었다리눅스 64비트 환경에서 인자를 넘겨줄 때는 첫번째 인자는 rdi 레지스터를 이용해 넘겨준다그렇다는건 rdi 레지스터에 /bin/sh 이라는 문자열 주소를 넣고 ret으로 system을 실행시켜야하는데….
 
** 맞다.! 나는 stack smashed가 카나리 변조만으로 이루어지는 줄 알았다하지만 카나리 값을 제대로 넣어도 stack smased가 나오는 경우가 있었다바로 rsp의 위치였다리눅스 64비트에서 디버깅을 해보니 rsp 가 아무역할을 안하는거 같길래 무시했더니, rsp가 rbp보다 큰주소(아래)주소에서 놀고 있을 때 stack smashed가 일어났다함수 시작 앞에서 rsp를 sub로 조정하는 부분이 불필요한 부분은 아니었던 것이다
이 부분으로 또 한참이 걸렸다.
이 과정에서 나는 ROP를 생각했다이 때 fake rbp를 이용해 스택 포인터를 마음대로 움직여야겠다는 생각도 하였다그러면서 ROP를 해야겠다는 생각이 들었다
그래서 ROP 가젯을 찾기 위해 새로운 프로그램들을 받으면서 경험했다.
 

문제 해결에 도움을 준 프로그램은 ROPgadget이라는 프로그램이었다여기서 엄청 핵심인 가젯을 찾아주었다.



(퍼펙트 가젯)



아니…! Pop rdi !! 라니!!!!!! 게임 끝이지 뭐

Fake rbp를 이용해 스택 포인터를 버퍼쪽으로 가져간 후 여기서 pop rdi 할 때 스택 위치에 /bin/sh 문자열을 넣을 주소를 넣어주고 ret 에 system 주소를 넣어준다그리고 /bin/sh 문자열은 버퍼의 어딘가 위치에 넣고 그 offset만 맞추어서 pop rdi에 들어가게 하면 된다.


(exploit 코드)



exploit 해주면



(문제 해결)

'WarGame > 500 Project' 카테고리의 다른 글

(63/500) pwnable.kr - syscall  (2) 2017.10.22
(62/500) NOE.systems - BURYBURY  (0) 2017.10.01
(60/500) pwnable.kr - crypto1  (0) 2017.08.27
(59/500) pwnable.kr - dragon  (0) 2017.08.17
(58/500) pwnable.kr - fsb  (0) 2017.08.12

+ Recent posts