[Dreamhack] Bypass NX & ASLR: 2 - Library - Static Link vs. Dynamic Link

securitykss·2022년 11월 2일
0

Pwnable 강의(dreamhack)

목록 보기
18/58
post-thumbnail

이 글은 https://dreamhack.io/lecture/courses/66 을 토대로 작성한 글입니다.

1. Introduction

Library를 직역하면 도서관이다. 도서관에는 여러 책들이 있고, 그 책들에는 여러 정보들이 담겨져 있다.

컴퓨터 시스템 관점에서도 이 라이브러리는 비슷한 개념이다.

먼저 이 라이브러리에 대해 알아보자.

2. Library

라이브러리는 컴퓨터 시스템에서, 프로그램들이 함수나, 변수를 공유해서 사용할 수 있게 한다.

C 언어로 프로그래밍을 할 때, printf나 scanf 등 이런 함수들을 사용할 수 있는 것은

이미 라이브러리 안에 이런 함수들이 정의가 되어 있기 때문이다.

3. Link

링크는 컴파일의 마지막 단계이다. 프로그램에서 printf 같은 라이브러리 함수를 사용한다면, 호출된 함수와 실제 라이브러리의 함수가 링크 과정 통해 연결된다.

이해를 돕기 위해 간단한 C 코드를 컴파일을 해서 알아보자.

//gcc -o example example.c

#include<stdio.h>

int mai() {
	puts("hihi\n");
    return 0;
}

여기서 GLIBC는 라이브러리를 의미한다.

example이 어떤 라이브러리와 링킹이 되어있는지에 대한 정보를 알 수 있다.

정리하자면, gcc로 컴파일 할 때 라이브러리가 링킹 된다.

링크 과정을 거친 후, 프로그램에서 puts를 호출할 때, 라이브러리에 정의되어 있는 puts를 찾아서 해당 코드를 실행하게 된다.

라이브러리는 크게 동적 라이브러리와 정적 라이브러리로 구분된다.

동적 라이브러리를 링크하는 것을 Dynamic Link(동적 링크),

정적 라이브러리를 링크하는 것을 Static Link(정적 링크)라고 부른다.

이에 대해 알아보자.

3.2.1 설명

만약, 사람이 어떤 논문을 작성하고 있다고 가정해보자.

논문을 작성하는 데에 필요한 정보들은 도서관에 있다면,

Dynamaic Link는 논문과 관련된 정보들을 도서관에 있는 책을 찾고, 빌린 후, 책에서의 정보를 인용한다.

또 다른 정보들을 얻으려면 다른 책을 찾고, 빌린 후, 책에서의 정보를 가져온다.

프로그램도 마찬가지로 동적 링크된 바이너리를 실행하면 동적 라이브러리가 프로세스 메모리에 매핑된다.

(이는 어느 도서관의 책들을 빌릴지 정하는 것과 비슷하다.)

그리고 실행 중에 라이브러리의 함수를 호출하면 매핑된 라이브러리에서 호출할 함수의 주소를 찾고, 그 함수를 실행한다.

(이는 논문에서 필요한 내용을 그 도서관의 책을 찾고, 책의 정보를 가져와서 논문에 그 정보를 쓰는 것과 비슷하다.)

3.2.2 동적 링크 컴파일

gcc -o dynamic filename filename.c 로 컴파일 할 수 있다.

'dynamic', 이 옵션을 사용하지 않아도 gcc 컴파일러는 dynamic link를 한다.

3.2.3 동적 링크 장점

정적 링크에 대해서도 알아보겠지만,

동적 링크는 정적 링크에 비해 훨씬 적은 용량을 차지한다.

왜냐하면, 동적 링크는 필요한 정보만 빌려서 쓰기 때문이다.

3.2.4 동적 링크 단점

동적 링크된 바이너리의 동적 라이브러리가 프로세스에서 호환이 안 된다면, 실행이 안 될 수도 있다.

이 외에도 여러 단점들이 있다.

3.3.1 설명

마찬가지로 위에서 비유했던 것처럼,

만약, 사람이 어떤 논문을 작성하고 있다고 가정해보자.

논문을 작성하는 데에 필요한 정보들은 도서관에 있다면,

논문에 필요한 정보들을 도서관에 있는 모든 책을 다 가져와서 암기한 후, 논문을 작성한다.

프로그램에서도 마찬가지로 정적 링크를 하면 바이너리에 정적 라이브러리의 필요한 모든 함수가 포함된다.

(이는 논문에 필요한 정보들을 도서관에서의 책들을 다 빌려와 책의 정보를 암기하는 것과 비슷하다.)

따라서 해당 함수를 호출할 때, 라이브러리를 참조하는 것이 아니라, 자신의 함수를 호출하는 것처럼 호출할 수 있다.

(이는 논문에서 필요한 정보를 가져오려고 할 때, 이미 정보를 논문 저자가 외워버렸기 때문에, 도서관에서 빌려서 가져오는 것이 아닌, 스스로 논문에 쓸 수 있는 것과 비슷하다.)

3.3.2 정적 링크 컴파일

gcc -o static filename filename.c 로 컴파일 할 수 있다.

정적 링크를 하기 위해서는 'static', 이 옵션을 반드시 명시해야한다.

3.3.3 정적 링크 장점

동적 링크는 라이브러리에서 함수들을 찾는 데에 시간이 걸리지만,

정적 링크는 라이브러리 함수가 바이너리에 매핑이 되어 있기때문에 찾는 시간이 걸리지 않는다.

3.3.4 정적 링크 단점

위의 동적 링크의 장점이 곧 정적 링크 단점이 된다.

다시 말해, 정적 링크는 라이브러리의 함수들을 바이너리에 포함시키기 때문에 용량이 큰 단점이 있다.

4. PLT & GOT

4.1 설명

PLT(Procedure Linkage Table)와 GOT(Global Offset Table)는 라이브러리에서 동적 링크된 심볼의 주소를 찾을 때 사용하는 테이블이다.

4.2 순서

바이너리에서 처음으로 라이브러리 함수 호출

-> 라이브러리에서 심볼들을 탑색

-> 해당 함수의 정의 발견

-> 이 함수의 주소로 rip 실행 흐름 변경

이 전 과정을 runtime resolve 라고 한다.

계속해서 호출되는 함수의 정의를 탐색해야 한다면 비요율적이다.

따라서 ELF는 GOT라는 테이블을 두고, resolve된 함수의 주소를 해당 테이블에 저장힌다.

그리고 나중에 다시 해당 함수를 호출하면 저장된 주소를 꺼내서 사용한다.

4.3 C code 예제

// Name: got.c

// Compile: gcc -o got got.c

#include <stdio.h>

int main() {

  puts("Resolving address of 'puts'.");

  puts("Get address from GOT");

}

4.3.1 resolve 되기 전

got.c를 컴파일하고, 실행한 직후 GOT를 확인해보자.

got에 0x401030이 적혀 있다.

좀 더 알아보기 위해 puts@plt를 호출하는 부분에 break를 건 후 실행해보자.

si 명령어를 통해 puts@plt로 들어가보자.

puts@plt의 내부에서 got에 적혀있던 0x401030으로 jmp한다.

좀 더 실행하다보니 dl_runtime_resolve_xsavec라는 함수가 나온다. 이 함수에서 puts의 주소가 구해지고, GOT에 주소가 써진다.

여기까지가 puts 함수의 주소가 got에 resolve되는 과정이다.

4.3.2 resolve 된 후

다시 main으로 돌아와 두번째 puts@plt를 호출해보자.

put@plt로 들어가기 전에, got를 확인해 보니, 라이브러리의 puts함수가 적혀져 있는 모습을 확인할 수 있다.

got에 이미 puts함수의 주소가 적혀져 있으므로, put@plt는 puts로 jmp를 한다.

4.3.3 resolve 간단 정리

PLT에서 해당 함수 처음 호출

-> dl_resolve 과정을 거쳐 GOT에 라이브러의 해당 함수의 주소를 남김.

-> PLT에서 해당 함수 두번째 호출

-> GOT에 해당 함수의 주소가 적혀져 있음

-> PLT에서 바로 참조가 가능

4.3.4 GOT 취약점?

PLT에서 GOT를 참조하여 실행 흐름을 옮길 때, GOT의 값을 검증하지 않는다.

따라서 GOT에 저장된 해당 함수의 주소를 공격자가 임의로 변경하여 실행 흐름을 공격자로 옮길 수가 있다.

이런 공격 기법을 GOT Overwrite라고 부른다.

5. Conclusion

이렇게 라이브러리, 동적 링크와 정적 링크, 그리고 PLT&GOT에 대해 알아보았다.

마치며

다음 시간엔 NX를 우회하는 공격 기법으로 Return to Library를 알아보자.

Reference

https://dreamhack.io/lecture/courses/66

profile
보안 공부를 하는 학생입니다.

0개의 댓글