Hacking Note/System Hacking

PWN - 0x00 - 시스템 해킹을 시작하는 길

LittleDev0617 2020. 9. 16. 00:49

포너블이 처음이라면, 1년전의 내가 이 글을 봤을때 갈피가 잡히게끔 주저리주저리 해보겠다.

 

CTF에서 포너블 문제는, 결국 서버 쉘을 따내는 것이다.

쉘을 따내는데 쓰이는 기법에 따라 풀이가 달라진다.

 

기본적으로 쉘을 따려면, system("/bin/sh"); 을 실행해야한다.(exec 등등)

이 구문을 실행하기 위해 수십가지의 방법들이 있고, 그 방법들을 막는 보호기법이 걸려있고, 그 기법을 우회하는 공격이 나오고... 이것들을 많이 아느냐 모르느냐가 실력의 지표라고 생각한다.

 

Stack Frame

아주 기초로 가보자면, 어떤 함수가 끝을 내릴때, 다시 돌아갈 주소가 있어야 돌아갈 수 있다.

중학교때 비유해서 공부했던 기억을 되살려보면, 장보러 가기 위해 메모장에 구매 목록을 써놨는데, 화장실 갔다온 사이 누군가가 구매 목록을 임의로 조작하고, 나는 그것을 모른채 그저 사버린 그런 느낌이다.

 

함수의 프롤로그와 에필로그 부분을 봐보자.

push rbp

mov rbp, rsp

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

leave

ret

위가 프롤로그, 아래가 에필로그인데, 프롤로그에선 현재 스택 프레임의 바닥(RBP)를 push한다.

그 후, RBP를 RSP까지 맨위로 올려버린다.

그 후, 함수가 끝날때는 leave ret 하는데, leave 는 

mov rsp, rbp

pop rbp

라고 보면 된다. 즉, 전 스택 프레임의 RBP를 복구했다고 볼 수 있다.

그러면 현 스택 최상단에는 RET 주소만이 남아있고, RET

pop rip

jmp rip

를 통해 코드 흐름을 바꾼다.

 

이제, 이 RET 값을 Buffer Over Flow, Format String Bug, Out Of Boundary 등등을 이용해 바꾸고, 더 나아가서

Shell Code, Return To Libc, Return Oriented Programming (ROP) 등을 이용해 

여러 보호기법들을 우회하는 것까지가 스택 관련 exploit 이라 생각하면 될 것 같다.

 

Shell Code

보통 포너블 입문 문제로 많이 나오는데, 스택에 쉘코드를 입력하고, 

RET 주소를 스택 쉘코드가 위치한 주소로 바꿔

쉘코드가 실행되게끔 하는 공격이다.

하지만 이는 NX bit 보호기법으로 코드 영역이 아닌 부분에서는 코드 가 실행이 안되게끔 막기 때문에,

못 쓰는 경우가 많다.

 

Return and Return Return.....

여기서부터 슬슬 초심자 입장에서 머리가 꼬이기 시작할 것이다.

일단 plt 와 got 의 개념에 대해서 알아야하는데,

간단히 설명하자면 함수를 호출할때 dynamic linking binary면 컴파일 시에 모든 라이브러리

함수를 로드하지 않고, 동적으로 부르기 때문에, plt 와 got가 활용된다.

함수를 호출할때 CALL printf@plt 이런 식으로 printf의 plt 주소를 호출하고,

plt에는 어셈 코드가 있다.

현재 해당 함수가 처음 호출된다면, 해당 함수의 라이브러리 주소를 구하고,

이를 해당 함수의 got 에다가 쓴다. 그리고 다시 함수가 호출되면

got에 써진 라이브러리 함수 주소로 넘어가는 방식이다.

 

자, 이 개념이 왜 필요하냐,

바이너리에 system 함수가 안쓰인 경우가 훨씬 많을 텐데,

그러면 system 함수 주소를 따로 알아내야한다. 

결론부터 말하면, 이미 한번 호출된 라이브러리 함수의 got 영역을 LEAK 하면

링크된 라이브러리의 주소를 알아낼 수 있다.

 

라이브러리 함수는 해당 라이브러리 BASE 로부터 일정한 오프셋에 떨어져있는데,

이 오프셋을 알고 libc base 를 알면 해당 라이브러리의 모든 함수 주소를 알아낼 수 있는 것이다.

 

예를 들어 read 함수가 base로부터 0x100 만큼 떨어져있는데,

read 함수의 got 를 출력해보니 0x200(실제론 0x7f~~) 이면, libc_base는 0x100 인것이다.

 

그러면 여기서 또 의문, 라이브러리 got 를 어떻게 출력하는데?

 

이제 여기서부터는 다음 글에서 ROP 에 대해 다루면서 자세하게 써볼 것이다.

 

 

처음 포너블을 공부할때, 개념 하나 잡기도 벅찬 그 느낌과 여러 선배분들의 블로그를 보면서 

신기함과 동시에 여러 작은 꿀팁들이 큰 도움이 됐다고 생각하기에,

나도 열심히 글을 남겨서 도움이 될 수 있으면 좋겠다고 생각한다.