1) ASLR(Address Space Layout Randomization)

=스택, 힙, 라이브러리 등의 주소를 랜덤으로

/proc/self/maps로 확인

해제:

echo 0 > /proc/sys/kernel/randomize_va_space

randomize_va_space=0 : ASLR 해제

randomize_va_space=1 : 스택 & 라이브러리

randomize_va_space=2 : 스택 & 라이브러리 & 힙


특정 바이너리에서만 비활성화

setarch `uname -m` -R ./yourProgram


ldd로도 확인가능, 라이브러리 기본주소 임의로 지정

-->System 함수노출을 위한 libc.so.6 기본주소 + offset 연산, 

libc.so.6을 얻기위한 __libc_start_main 주소 노출

_start함수에서 __libc_start_main을 호출하기에 got에 함수 주소가 올라감을 이용


2) DEP(Data Execution Prevention), NX(W^X)

=데이터 영역의 실행 방지

DEP 제거 = 스택, 힙 실행 허용 = -z execstack 옵션으로 gcc 컴파일 (gcc -z execstack ~~.c -o ~~)

-->RTL, ROP


3) ASCII-Armor

=공유라이브러리 영역의 상위 주소에 0x00을 포함시킴

RTL(Return to library)방어

libc의 특정 함수로 뛰는 것 방어

-->


4) Stack Canary

=로컬 변수와 SFP(Saved Frame Pointer)사이에 특정한 값을 추가 후 확인

프롤로그 이후(프롤로그에서 SFP저장), gs: Thread Control Block (which stores Thread Local Storage, aka TLS)영역에서 값을 가져와서 저장후 마지막에 확인, 확인시 다시 gs와 비교후 다르면 __stack_chk_fail@plt로 점프

1. Terminator canaries

2. Random canary

3. Null canary

-->fork 이용한 4바이트 한자리씩 예측


5) RELRO

GOT Overwrite 공격

=다른 함수의 주소로 덮어씌워서 임의의 함수 실행

Lazy Binding: Dynamic Linking 방식으로 컴파일 시에 공유 라이브러리 내의 함수 주소를 GOT(Global Offset Table)을 통해 동적으로 알아온다.

Dynamic link: 공유 라이브러리를 하나의 메모리 공간에 매핑하고 여러 프로그램이 사용

그래서 실제 코드가 없고 PLT, GOT를 사용 https://looka149.tistory.com/entry/PLTGOT

함수실행 -> PLT -> GOT값으로 jmp (처음실행시에는 PLT+6으로 이동해서 실제 주소를 가져옴 // 두번째부터는 실제 주소)

이때 GOT의 값을 임의의 함수의 주소로 덮어씌우면 끝

PLT (Procedure Linkage Table)

GOT (Global Offset Table)

이를 막기위한 것으로

스크린샷 2016-05-18 오후 3.47.59.png

출처: https://bpsecblog.wordpress.com/2016/05/18/memory_protect_linux_2/


읽기 전용 섹션으로 만들어서 수정을 방지

섹션들의 정보는 objdump -h 바이너리명으로 확인가능


Dafult  :  .ctors, .dtors, .jcr, .dynamic, .got  -> 수정가능

Partial :  .ctors, .dtors, .jcr, .dynamic        -> 읽기전용    .got -> 수정가능

Full    :  .ctors, .dtors, .jcr, .dynamic, .got  -> 읽기전용


그러나 속도때문에 Partial을 많이 쓴다.


6) PIC(Position Independent Code)


정적 라이브러리(Static Library)는 오브젝트 파일(.o)을 모아서 ar rv로 묶은 라이브러리 파일(.a)

gcc -c def.c 

ar rv lib_static_def.a def.o


def.c에서 정의한 함수를 call.c에서 호출 후


gcc call.c -o call lib_static_def.a 하면 정적으로 포함하여 컴파일



공유 라이브러리는 실행시에 공유 라이브러리를 참조하도록 함

gcc -c -fPIC def.c

gcc -shared -o lib_dynamic_def.so def.o

= gcc -shared -fPIC -o lib_dynamic_def.so def.c

$ vi /etc/ld.so.conf 을 보면 

include /etc/ld.so.conf.d/*.conf 라고 적혀있다. == /etc/ld.so.conf.d/ 디렉토리 안에 [아무말].conf로 파일을 만들고 안에 lib_dynamic_def.so의 폴더경로를 적음


후에 ldconfig 명령어 입력



이렇게 되면 다른 모든 실행파일 내에서 사용 가능


def.c에서 정의한 함수를 사용하는 call.c라는 파일을 만든 후


gcc call.c -o call -lmy -L. 을 이용하여 공유라이브러리 링킹

(-l 옵션은 앞의 lib과 뒤의 a이나 so를 떼고 진행 libaaa.a -> -laaa, libmy.so -> -lmy)

(-L 옵션은 라이브러리의 위치를 지정해줌)

(리눅스에선 기본적으로 /lib, /usr/lib, /usr/local/lib 만 검색)



ldd(List Dynamic Dependencies)을 이용하여 확인 가능



gcc -shared -o A.so A.c

gcc -shared -fPIC -o B.so B.c 

두개가 있을 경우 PIC 유무의 차이인데 이는 재배치의 차이로 이어진다.


readelf -d 옵션을 통해 TEXTREL과 RELCOUNT를 살펴보면 둘 다 기본적으로 gcc가 기본적으로 사용하는 시작 파일의 코드로인해 RELCOUNT가 3이고(-nostartfiles로 없앨 수 있음) 재배치 횟수만큼 A.so와 B.so가 차이가 난다. noPIC이 그만큼 더 많다.


noPIC의 경우 내부의 printf 함수를 .text섹션에서 호출

PIC의 경우 plt을 거쳐서 printf를 호출한다.



Relocatable code는 재배치가 필요함. 따라서 .text영역에 이를 표시해 두고 로더가 이후에 이 영역의 값을 변경함 

이는 곧 다른 위치로 로드된 동일한 코드는 이를 사용할 수 없다는 것이므로 공유 라이브러리의 개념과 맞지 않아서

PC-relative 방식의 link time에 계산된 오프셋만을 이용하는 PIC를 사용함.




7) PIE(Position Independent Executable)

6은 라이브러리를 위한 것


PIE는 전체가 위치 독립 코드로 이루어진 실행 가능한 바이너리


6처럼 so를 만들고 연결해주고


so안의 함수를 call하는 test.c라는 파일을 만들고, 전역 *buf = "hello"의 위치를 호출하는 코드 address.c를 만들고.


gcc -o test_no_PIE test.c

gcc -fPIE -pie test_yes_PIE test.c 


gcc -o address_no_PIE address.c

gcc -fPIE -pie address_yes_PIE address.c 를 통해 두가지 버전을 만들면

PIE버전의 주소는 계속 변한다. --> PIE는 위치 독립 실행파일로, 실행할 때마다 매핑되는 주소가 어디든지에 상관없이 실행가능 -> 매번다름


또한 file 명령어를 통해 안을 보면

no_PIE는 executable로

PIE는 shared object로 나온다.


일반 실행 파일은 puts를 plt를 이용하여 호출한다. 이때 주소는 고정되어있다. 뿐만 아니라 사용자 함수도 고정되어 있다.


PIE 파일은 puts@plt를 call 하는 것은 같지만 주소가 매우 다르다.

뿐만아니라 __x86.get_pc_thunk.bx와 같은 함수를 볼 수 있다. 이는 다음 실행할 EIP를 EBX로 옮기는 명령어다.

이를 통해 상대적으로 주소를 계산한다. 어떻게? ebx에 X를 더하는 명령어를 실행함으로써 .got.plt 섹션의 주소를 가르키도록 만든다.


X = “got영역의 주소(오프셋)” – “add 인스트럭션의 주소(오프셋)” 이다. 다 상대주소(오프셋)기때문에 가능하다!


더 자세한설명은 블로그에 있다.


또한 -fPIC -pie 의 의미는 각각 컴파일러, 링커를 위한 옵션이다.






출처: 

https://hackability.kr/entry/%EC%8B%9C%EC%8A%A4%ED%85%9C-%ED%95%B4%ED%82%B9-101?category=577654

https://bpsecblog.wordpress.com/memory_protect_linux/