본문 바로가기

System/Memory Mitigations

PIE

PIE(Position-Independent Executable) : ASLR이 코드 영역에도 적용되게 해주는 기술

 

PIE 설정

gcc -no-pie PIE.c -o NoPIE

gcc를 할 때 -no-pie를 설정해주면 PIE 기법이 적용되지 않는다.

gcc PIE.c -o PIE

아무런 설정을 하지 않을 경우 default로 PIE가 적용된다.

 

Example

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *global = "Lazenca.0x0";

int main(){
    char *heap = malloc(100);
    char *stack[] = {"LAZENCA.0x0"};

    printf("[Heap]  address: %p\n", heap);
    printf("[Stack] address: %p\n", stack);
    printf("[libc]  address: %p\n",**(&stack + 3));
    printf("[.data] address: %p\n",global);
    free(heap);
    return 0;
}
gcc -no-pie PIE.c -o NoPIE

PIE가 설정되지 않았을 때, 데이터 영역의 주소가 변경되지 않는다.

 

gcc PIE.c -o PIE

반면, PIE가 설정됐을 때, 데이터 영역이 변경되는 것을 확인할 수 있다.

 

PIE 우회

PIE가 설정된 문제일 경우, 데이터 영역과 코드 영역의 주소가 달라지는 것을 유의해야 한다. 

 

Example - Code base

#include <stdio.h>

int global_variable = 1;

int sum(a,b)
{
        return a + b;
}

int main()
{
        printf("global variable: %p\n", &global_variable);
        printf("function sum: %p\n", &sum);
        return 0;
}

위는 전역 변수의 주소와 함수의 주소를 출력해주는 코드이다.

 

PIE가 설정되지 않았을 때, 전역 변수의 주소와 함수의 주소는 변경되지 않는다.

반면, PIE가 설정됐을 때, 전역 변수의 주소와 함수의 주소 변경된다.

 

ASLR이 적용된 문제와 마찬가지로, 전역 변수의 주소에서 data 영역의 주소로 빼서 offset을 구하고, 함수의 주소에서 코드 영역의 주소로 빼서 offset을 구할 수 있다. 

 

구한 offset들로 문제에서 출력해주는 각각의 주소들을 빼서 base 주소를 구하여 PIE가 적용된 문제를 해결할 수 있다.

 

Partial Overwrite

반환 주소의 일부 바이트만 덮는 공격을 Partial Overwrite라고 한다.

 

ASLR의 특성 상, 코드 영역의 주소도 하위 12비트(1.5bytes) 값은 항상 같다.

gloabl variable의 주소 하위 12비트인 0x010과 function sum의 주소 하위 12비트인 0x149는 프로그램을 다시 실행시켜도 동일한 것을 확인할 수 있다.

따라서 코드 가젯의 주소가 반환 주소와 한 바이트만 다르다면, 이 값만 덮어서 원하는 코드를 실행시킬 수 있다.

 

'System > Memory Mitigations' 카테고리의 다른 글

NX Bit  (0) 2024.05.24
ASLR  (0) 2024.05.23