[Pwnable] PIE (위치 독립 실행 파일)
ASLR은 바이너리가 실행될 때마다 스택,힙,공유 라이브러리 등이 무작위 주소에 매핑되는 보호기법이었습니다.
하지만, 실행파일의 main()이나 전역 변수 등이 위치한 주소는 항상 고정된 상태였는데, PIE는 ASLR이 코드 영역에도 적용되게 해주는 기술입니다.
PIE가 적용된 파일의 경우 공격자가 베이스 주소 유출 없이는 가젯이나 심볼의 주소를 맞추기가 굉장히 힘들어집니다.
리눅스에서 ELF에는 실행파일과 공유 오브젝트(SO)의 두가지가 존재하는데, 공유 오브젝트는 libc.so와 같은 라이브 파일을 의미합니다.
공유 오브젝트는 메모리의 어느 주소에 적재되어도 코드의 의미가 훼손되지 않게 설계되어 있는데, 이런 코드를 PIC라고 합니다.

저번 워게임 문제를 풀때 다운로드 받은 libc.so.6을 읽어보면 대부분이 R_386_RELATIVE같은 재배치 형식으로 되어있습니다.
저희가 저번에 문제를 풀 때 read함수가 적재되는 메모리에서 libc.so.6이 매핑되는 주소를 빼서 베이스 주소를 구하고 거기에다 system함수의 주소를 더하는 방식으로 system함수의 주소를 구했습니다.
이렇게 내부의 함수를 베이스주소에 오프셋을 더하는 구조로 재배치를 하는게 pic코드의 작동 방식입니다.
pic.c를 다음과 같이 작성해서 확인해보겠습니다.
gcc -o pic pic.c #pic
no_pic pic.c -fno-pic -no-pie #no pic
위의 방식으로 두가지 방식으로 컴파일을 해주고 gdb로 열어보겠습니다.
먼저 pic가 적용되지 않은 no_pic입니다.

메인함수도 0x40113e로 고정된 값을 사용하고 있습니다.

edi에 0x402013이라는 주소를 직접 호출해서 printf에 넣고 있습니다.
다음으로 pic가 적용된 pic파일입니다.

메인함수의 주소도 RVA로 작은 주소로 보이는데 실행될 때는 ASLR이 더해져 base주소가 더해진 곳에서 main이 실행되게 됩니다.

printf의 인자도 rip를 기준으로 상대 참조하여 호출하고 있습니다.
PIC와 PIE를 비교해보면 PIC는 재배치가 가능한 코드라면, PIE는 재배치가 가능한 실행파일을 의미합니다.
재배치가 가능하기 위해서 PIE형식은 PIC코드로 만들어진 공유 라이브러리와 비슷하게 어느 베이스 주소에 올라가도 작동 가능하게 끔 main까지 상대 주소로 실행 가능합니다.
결과 같은 파일이어도 매번 실행할 때마다 main() 의 주소가 랜덤으로 바뀌는 형태입니다.
해당 코드는 드림핵에서 제공하는 PIE가 적용된 함수에서의 주소를 확인하기 위한 코드입니다.
gcc -o pie addr.c -ldl
다음의 명령어로 컴파일을 해주면 실행할 때 마다 영역별 주소를 획득할 수 있습니다.

세 번 실행한 결과입니다.
보면 매번 함수들의 주소가 달라지는 것을 확인할 수 있습니다.
하지만 main 함수에서 빨간색 부분을 제외한 1c9 부분과, 각 실행시마다 libc_base와 printf의 주소가 어느정도 겹치는
걸 확인할 수 있습니다.
이 부분을 이용해 PIE 우회를 시도할 수 있는데, ASLR의 특성상 코드 영역의 주소도 하위 12비트의 값은 항상 같습니다.
따라서 원하는 코드 조각의 주소가 반환주소와 한 바이트만 다르다면, 한 바이트만 브루트 포싱을 하면 원하는 코드를 실행시킬 수 있습니다.
이러한 공격을 Partial Overwrite라고 하며 다음에 워게임 문제를 풀면서 자세하게 실습해 보도록 하겠습니다.
이상으로 포스팅을 마치겠습니다. 읽어주셔서 감사합니다~