ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Integer Overflow, Underflow / Signedness bugs / Widthness bugs
    보안개론 2024. 6. 4. 16:08

    아리안 5

    적재된 위성을 궤도에 전달하기 위한 용도의 로켓
    64비트 숫자를 16비트에 채우면서 유발

     

    화성 기후 궤도 탐사선

    록히드 마틴에서는 점화 데이터를 야드 단위로 만들었고,

    나사는 미터법으로 생각했음 -> 지나치게 낮은 궤도 - 폭발

     

    비트 크기를 제대로 맞추지 않으면 문제가 생길 수 있음


     

    char: -128~127

    unsigned char: 0~255

    short: -32768~32767

    unsigned short: 0~65535

     

    Format Specifier

    %d - 10진수 정수 (4바이트)

    %u - 부호없는 정수

    %i - 아무 정수 (10진수, 8진수, 16진수)

     

    %hd - short (2바이트)

    %hu - unsigned short

     

    %hhd - char (1바이트)

    %hhu - unsigned char

     

    %ld - long (32비트 시스템이면 4바이트, 64비트 시스템이면 8바이트)

    %lu - unsigned long

     

    %o - 8진수 정수, 4바이트

    %x - 16진수 정수, 4바이트

     

    %p - 주소 출력, 32비트 시스템이면 4바이트, 64비트 시스템이면 8바이트 .. 인데 보통 48비트만 사용


    Integer overflow / Wraparound

    CWE 190

     

    정수가 범위를 넘어선 너무 큰 값으로 증가하면 0이나 음수가 됨 (오버플로우)

     

    CIA를 깨트릴 수 있음

    가용성

    - 정의되지 않을 작동으로 연결되어 크래시 발생 가능,  반복문의 인덱스에서 인티저 오버 플로우 발생 시 무한 루프에 빠져 정상 작동하지 않을 수 있음

     

    무결성

    - 문제가 되는 값들이 중요한 데이터이면 단순한 데이터 오염 발생

    - 랩 어라운드가 발생하여 버퍼 오버플로우로 연결 시 메모리 오염 발생 가능

     

    비밀성, 가용성, 접근 제어 등 ..

    - 임의 코드 실행으로 연결될 수 있음


    Signed Numbers

    Binary Decimal Hexadecimal
    0111 1111 127 0x7F
    0111 1110 126 0x7E
    1111 1111 -1 0xFF
    1111 1110 -2 0xFE
    1000 0001 -127 0x81
    1000 0000 -128 0x80

     

    양수 127

    2진수 - 0111 1111

    1의 보수 -> 1000 0000

    2의 보수 -> 1000 0001

     

    2 +(-3) = ?

    3 : 이진수로 0011

    1의 보수 -> 1100

    2의 보수 -> 1101

    0010 + 1101 = 1111 -> -1

     

    4비트로 제한되어 있다고 치자

    +5 + 4

    0101 + 0100

    1001 -> 오버플로우

     

    -7 -6

    1001 + 1010

    1 / 0011 -> 오버플로우

     

    32비트의 경우

    int 최고 -> 0x7FFFFFFF (2147483647)

    여기다 1 더하면 -> 0x80000000

    => 언더플로우

     

    img_t table_ptr;
    int num_imgs;
    num_imgs = get_num_imgs();
    table_ptr = (img_t*)malloc(sizeof(img_t) * num_imgs);

    malloc 내부 인자 값이 엄청 커져서 오버플로우가 발생할 수도 있음

    대신 xmalloc 권장

     

    같은 이유로 memcpy도 문제가 있음

     

    int catvars(char *buf1, char *buf2, unsigned int len1, unsigned int len2) {
        char mubuf[256];
        
        if( (len1 + len2) > 256 ) {
            return -1;
        }
        
        memcpy(mybuf, buf1, len1);
        memcpy(mybuf + len1, buf2, len2);
        
        do_some_stuff(mybuf);
        
        return 0;
    }

    len1과 len2를 더해서 오버플로우 발생 시 256보다 작을 수 있음

     

    계산 결과이후 저장된 결과와 올바른 결과가 다를 수 있음

    중요한 변수에 잘못된 값을 포함하게 하는 등, 문제가 될 수 있음

     

    어떻게 예방할 수 있는가?

    에러 핸들링, 익셉션 핸들링

    int sum(int a, int b) {
        int c = a + b;
        if( a > 0 && b > 0 && c < 0 ) {
            throw new MyOverflowException(a, b);
        }
        return c;
    }
    
    int pord(int a, int b) {
        int c = a * b;
        if( a > 0 && b > 0 && c < 0 ) {
            throw new MyOverflowException(a, b);
        }
        return c;
    }

    양수를 더했는데, 혹은 곱했는데 음수가 나오면 예외처리

     

    static void update_value(char op) {
        if( op == '+' ) {
            if( value + 1 > value ) value++;
            else printf("too big!\n");
        }
        else {
            if( value -1 < value ) value--;
            else printf("too small!\n");
        }
    }
    
    int addOvf(int *result, int a, int b) {
        if( a > INT_MAX - b ) return -1;
        else {
            *result = a + b;
            return 0;
        }
    }

    더했는데 원해 값보다 작아지거나,

    원래 값이 너무 커서 남은 자리가 충분하지 않은지 검사하기

     

    완화시키기(SDLC 단계에서 신경써야 함)

    요구사항 단계

    - 언어를 잘 선택해라: 파이썬같은 건 부족하면 알아서 늘림

     

    설계 단계

    - 라이브러리나 프레임워크를 잘 선택해라(SafeInt, IntegerLib)

     

    구현 단계

    - 입력 검증 하기

    - 크기를 나타내는 건 unsigned 쓰기


    Signedness bugs

    - 부호가 없는 변수가 부호가 있는 것으로 해석되는 경우

    - 부호가 있는 변수가 부호가 없는 경우로 해석되는 경우

     

    // int.c
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[]) {
        char buf[20];
        
        int i = atoi(argv[1]);
        memcpy(buf, argv[2], i * sizeof(int));
    }
    // void *memcpy(void *dest, const void *src, size_t num);

    1. 버퍼 오버플로우

    ./ 111 AAAA

    i * sizeof(int) => 444

    444만큼 argv[2]의 내용을 카피? -- buf는 20바이트 크기 -> 넘침

    스택의 구조가 망가지고, 리턴 어드레스나 saved ebp가 망가지고, 스택 카나리가 망가짐 (스택 스매싱 detected)

     

    2. 부호화 버그로 인한 버퍼 오버플로우

    memcpy의 size_t는 unsigned integer임

    그런데 ./int -1 AAAA

    이런식으로 사이즈에 음수값을 주면 -1은 16진수로 0xffffffff

    0xffffffff를 memcpy에서 unsigned int로 받아들이면 굉장히 큰 숫자가 되어 버퍼 오버플로우 발생

     

    맥에서는 테스트 결과 애초에 버퍼 크기를 넘기면 안된다

    우분투에선 이렇게 된다

     

     

    프로세스 구조 중 스택은 위와 같다.

    여기서 버퍼 오버플로우가 발생하여 argc의 값까지 망가진 것을 볼 수 있다.

    무결성이 깨지는 문제

     

    CWE-195: Signed to Unsigned Conversion Error

    unsigned int readdata() {
        int amount = 0;
        ....
        if( result == ERROR ) amount = -1;
        ....
        return amount;
    }

    unsigned int로 -1을 리턴하면 엄청 큰 수가 리턴 될 것

     

    int copy_something(char *buf, int len) {
        char kbuf[800];
        
        if( len > sizeof(kbuf) ) {
            return -1;
        }
        
        return memcpy(kbuf, buf, len);
    }

    len이 음수이면 if문은 통과하는데, memcpy에서 unsigned int로 컨버전되면서 엄청 큰 수로 바뀜


    #include <stdio.h>
    
    int main(void) {
        int i;
        short s;
        char c;
        
        i = 0xdeadbeef;	// 0xdeadbeef
        s = i;			// 0xbeef
        c = i;			// 0xef
        
        printf("i = 0x%x, (%d bits)\n", i, sizeof(i) * 8);	// 0xdeadbeef (32bits)
        printf("s = 0x%x, (%d bits)\n", d, sizeof(s) * 8);	// 0xffffbeef (16bits)
        printf("c = 0x%x, (%d bits)\n", c, sizeof(c) * 8);	// 0xffffffef (8bits)
        
        return 0;
    }

    d는 앞쪽 비트가 1 -> 사이즈 안맞추면 f로 차게 됨

    %hx, %hhx를 사용하기

     

    // width.c
    #include <stdio.h>
    #include <string.h>
    #incldue <stdlib.h>
    
    int main(int argc, char *argv[]) {
        unsigned short s;
        int i;
        char buf[80];
        if( argc < 3 ) return -1;
        
        i = atoi(argv[1]);
        s = i;
        
        if( s >= 80 ) {
        	printf("you don't");
            return -1;
        }
        
        printf("s=%d\n", s);
        memcpy(buf, argv[2], i);
        buf[i] = '\0';
        printf("%s\n", buf);
        
        return 0;
    }
    // ./width1 5 hello
    // s = 5
    // hello
    
    // ./width1 80 hello
    // you don't
    
    // ./width1 65536 hello
    // s = 0
    // Segmentation fault (core dumped)

    int에 65536 받아놓고 unsigned short로 검사 .. > 너무 커서 버퍼가 넘침

     

    '보안개론' 카테고리의 다른 글

    Byte Ordering, Simple Buffer Overflow  (0) 2024.06.04
    Array Operations  (0) 2024.06.04
    Use After Free  (0) 2024.06.03
    bin, chunk, double free  (0) 2024.06.03
    ptr[-1], ptr[-2]가 가지는 의미  (0) 2024.05.19
Designed by Tistory.