ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Byte Ordering, Simple Buffer Overflow
    보안개론 2024. 6. 4. 21:43

    Little endian

    - 높은 바이트가 높은 주소에 저장

    - 인텔 x86

     

    Big endian

    - 낮은 바이트가 높은 주소에 저장

    - PowerPC, SPARC

     

    Data: 0x01020304 0x100 0x101 0x102 0x103
    Little Endian 0x04 0x03 0x02 0x01
    Big Endian 0x01 0x02 0x03 0x04

    공격자들은 주소를 조작하기 위해 바이트 오더링 방식을 알아야 함


    CWE-121: Stack-based Buffer Overflow

    버퍼는 배열로 이루어진 임시 기억 공간

    제일 많이 할당되는 부분은 스택(지역변수)

    * 전역변수면 데이터 영역, malloc으로 할당 받았으면 힙 영역에 존재

    보통 스택에서 오버플로우가 많이 일어남

     

    Stack-based 버퍼 오버플로우

    * 그냥 스택 오버플로우에는 재귀함수로 스택을 소진시키는 것도 해당됨

     

    스택에는 지역변수, 리턴 어드레스, saved ebp

    스택 보호 기법이 있으면 스택 카나리까지 들어감

    지역 변수 중 버퍼가 있고, 넘치면 문제가 됨 (리턴 어드레스 조작 시 임의 코드 실행 가능)

     

    #include <stdio.h>
    
    void main() {
        char dum[4];
        int cookie;
        char buf[20];
        
        printf("buf: %p, &cookie: %p\n", buf, &cookie);
        
        gets(buf);
        
        if (cookie == 0x41424344)
            printf("you win!\n");
    }

    쿠키가 0x41424344 면 통과인데 왜 DCBA 순으로 들어가는가

    -> 실행환경이 인텔 cpu라 리틀 엔디안 ..

    스택 구조 상 DCBA로 넣어야 D가 더 낮은 주소에 들어가고 쿠키에 오버플로우되면 ABCD 순서로 들어가 있을 것

     

    #include <string.h>
    #include <stdio.h>
    #define goodPass “GOODPASS”
    int main() {
        char passIsGood = 0;
        char buf[28];
        
        printf("buf: %p, &passIsGood: %p\n", buf, &passIsGood);
        printf(“Enter password: \n”);
        
        gets(buf);
        
        if (strcmp (buf, goodPass) == 0) passIsGood = 1;
        if (passIsGood == 1)
            printf("you win!\n");
    }

    버퍼 28바이트 위에 passIsGood이 있을 것

    29번째에 \x01을 넣으면 1이 들어감

     

    #include <string.h>
    #include <stdio.h>
    #define goodPass “GOODPASS”
    int main() {
        char passIsGood = 0;
        short canary = 20;
        char buf[28];
        
        printf("buf: %p, &passIsGood: %p, &canary: %p\n", buf, &passIsGood, &canary);
        printf(“Enter password: \n”);
        
        gets(buf);
        
        printf("%d (0x%x\n)", canary, canary);
        
        if (strcmp (buf, goodPass) == 0) passIsGood = 1;
        
        if (passIsGood == 1)
            printf("you win!\n");
            
        return 0;
    }

    실제 카나리는 값이 바뀌는데, 예제로 short크기의 20 값을 가지는 카나리를 넣음

    이 카나리의 값이 오염되면 공격이 있다고 감지

    => 공격자들은 카나리의 값을 유지시키는 형태로 공격을 하고자 시도

     

    예측한다면 스택 보호기법도 껐으니 캐릭터 28바이트 + 카나리 2바이트 + 캐릭터 바이트 -> 31바이트 위치를 바꿔줘야 함

    하지만 실제론 32바이트 위치를 바꿔야 했음

    컴파일러가 모종의 이유로 이렇게 했을 것이고, 해커들은 이를 알아내려고 함

     

    어찌되었든, 카나리는 우회 가능함

    스택 카나리는 예측 가능하면 안됨

     

    위 예제에서는 파이썬을 사용해서 값을 주었음

    strcpy를 쓰는 경우엔 보통 펄로 값을 주고, gets를 쓸 때는 보통 파이썬으로 값을 줌

    버퍼 크기가 엄청 크더라도 프로그래밍 언어를 쓰면 공격하기가 쉬워짐

     

     

    - strcpy

    destination 사이즈를 고려하지 않고 그냥 복사

    - strncpy

    destination 사이즈 만큼 맞춰서 복사, 널 문자가 없어서 스트링 끝을 모름

    - strlcpy

    destination 사이즈 -1 만큼 복사하고 마지막에 널문자

    정보 손실은 있으나 다른 곳에 피해를 주지 않음

     

    영향

    가용성 - 도스(크래시, 종료, 리스타트), 도스(리소스 소모 - CPU), 도스(리소스 소모 - 메모리)

    무결성, 비밀성, 가용성, 접근제어 등 - 메모리 변조, 임의 코드 및 커맨드 실행, 프로텍션 패싱

     

     

    Mitigation

    완벽한 보안은 없음 -> 완화

    해커가 공격을 통해 얻는 이익보다 투자하는 시간, 비용이 더 들게 하면 됨

    그 방안들 ..

     

    페이즈: 컴파일

    - GS플래그(비주얼 스튜디오), FORTIFY_SOURCE GCC flag 등, 컴파일 단계에서 관련 플래그 사용

    - 스택 가드(카나리) 사용

     

    페이즈: 오퍼레이션

    - ASLR(Address Space Layout Randomization), PIE(Position-Independent Excutables) 사용

     

    페이즈: 설계

    - 안전한 라이브러리 사용

     

    페이즈: 구현

    - 인풋 범위 체크하기

    - gets같은 위험한 함수 쓰지 않기

     

    int main() {
        int arr[10];
        int buffer[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        buffer[15] = 100;
        buffer[20] = 50;
        buffer[30] = 75;
    }

    스택 보호 기법이 없다고 가정하면 buffer[15]는 arr을 건드림 => 실행은 됨

    buffer[20], buffer[30]? -> 실행은 될지 꺼질지 알 수 없음 (단순 유저 데이터만 오염될 시 실행은 됨)

     

    Q.

    1. buffer == &buffer[0] => O

    2. *(buffer + 1) => 2

    3. buffer = 500, (buffer + 1) = ? ... 504

    4. *(buffer + 2) == buffer[2] => O

    5. &buffer[0] = 500,

        &buffer[1] = ? .. 504

        arr = ? .. 540

        &arr[10] = ? .. 580

    6. buffer[10] = 11 -> arr[0] = 11 => O


    CWE-123: Write-What-Where Condition

    임의의 값을 임의의 위치에 쓸 수 있는 조건

    버퍼 오퍼플로우와 관련

     

    #define BUFSIZE 256
    
    int main(int argc, char **argv) {
        char *buf1 = (char *)malloc(BUFSIZE);
        char *buf2 = (char *)malloc(BUFSIZE);
        strcpy(buf1, argv[1]);
        free(buf2);
    }

    buf1의 영역을 벗어나 buf2의 영역을 침범하거나 메타데이터를 망가뜨릴 수 있는 코드

    특히 이전 청크나 다음 청크에 대한 정보를 망가뜨릴 수 있음

    이를 악용하여 임의 코드 실행이 가능

     

    이를 예방하기 위해 메모리 관리를 잘 해주는 언어를 쓰거나, 운영체제 레벨의 방어 기법 사용

Designed by Tistory.